summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/scala/reflect/api/Annotations.scala108
-rw-r--r--src/reflect/scala/reflect/api/BuildUtils.scala78
-rw-r--r--src/reflect/scala/reflect/api/Constants.scala13
-rw-r--r--src/reflect/scala/reflect/api/Exprs.scala10
-rw-r--r--src/reflect/scala/reflect/api/FlagSets.scala97
-rw-r--r--src/reflect/scala/reflect/api/ImplicitTags.scala119
-rw-r--r--src/reflect/scala/reflect/api/Importers.scala103
-rw-r--r--src/reflect/scala/reflect/api/Internals.scala1238
-rw-r--r--src/reflect/scala/reflect/api/JavaMirrors.scala56
-rw-r--r--src/reflect/scala/reflect/api/JavaUniverse.scala73
-rw-r--r--src/reflect/scala/reflect/api/Liftables.scala75
-rw-r--r--src/reflect/scala/reflect/api/Mirror.scala39
-rw-r--r--src/reflect/scala/reflect/api/Mirrors.scala58
-rw-r--r--src/reflect/scala/reflect/api/Names.scala71
-rw-r--r--src/reflect/scala/reflect/api/Position.scala167
-rw-r--r--src/reflect/scala/reflect/api/Positions.scala11
-rw-r--r--src/reflect/scala/reflect/api/Printers.scala79
-rw-r--r--src/reflect/scala/reflect/api/Quasiquotes.scala25
-rw-r--r--src/reflect/scala/reflect/api/Scopes.scala28
-rw-r--r--src/reflect/scala/reflect/api/StandardDefinitions.scala45
-rw-r--r--src/reflect/scala/reflect/api/StandardLiftables.scala235
-rw-r--r--src/reflect/scala/reflect/api/StandardNames.scala20
-rw-r--r--src/reflect/scala/reflect/api/Symbols.scala302
-rw-r--r--src/reflect/scala/reflect/api/TagInterop.scala43
-rw-r--r--src/reflect/scala/reflect/api/TreeCreator.scala3
-rw-r--r--src/reflect/scala/reflect/api/Trees.scala798
-rw-r--r--src/reflect/scala/reflect/api/TypeCreator.scala3
-rw-r--r--src/reflect/scala/reflect/api/TypeTags.scala8
-rw-r--r--src/reflect/scala/reflect/api/Types.scala466
-rw-r--r--src/reflect/scala/reflect/api/Universe.scala16
-rw-r--r--src/reflect/scala/reflect/api/package.scala7
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationCheckers.scala11
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationInfos.scala116
-rw-r--r--src/reflect/scala/reflect/internal/BaseTypeSeqs.scala47
-rw-r--r--src/reflect/scala/reflect/internal/BuildUtils.scala68
-rw-r--r--src/reflect/scala/reflect/internal/CapturedVariables.scala5
-rw-r--r--src/reflect/scala/reflect/internal/Chars.scala3
-rw-r--r--src/reflect/scala/reflect/internal/ClassfileConstants.scala17
-rw-r--r--src/reflect/scala/reflect/internal/Constants.scala39
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala1060
-rw-r--r--src/reflect/scala/reflect/internal/Depth.scala28
-rw-r--r--src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala10
-rw-r--r--src/reflect/scala/reflect/internal/FatalError.scala3
-rw-r--r--src/reflect/scala/reflect/internal/FlagSets.scala9
-rw-r--r--src/reflect/scala/reflect/internal/Flags.scala47
-rw-r--r--src/reflect/scala/reflect/internal/FreshNames.scala39
-rw-r--r--src/reflect/scala/reflect/internal/HasFlags.scala20
-rw-r--r--src/reflect/scala/reflect/internal/Importers.scala692
-rw-r--r--src/reflect/scala/reflect/internal/InfoTransformers.scala5
-rw-r--r--src/reflect/scala/reflect/internal/Internals.scala174
-rw-r--r--src/reflect/scala/reflect/internal/JMethodOrConstructor.scala47
-rw-r--r--src/reflect/scala/reflect/internal/JavaAccFlags.scala84
-rw-r--r--src/reflect/scala/reflect/internal/Kinds.scala193
-rw-r--r--src/reflect/scala/reflect/internal/Mirrors.scala131
-rw-r--r--src/reflect/scala/reflect/internal/MissingRequirementError.scala3
-rw-r--r--src/reflect/scala/reflect/internal/Mode.scala141
-rw-r--r--src/reflect/scala/reflect/internal/Names.scala348
-rw-r--r--src/reflect/scala/reflect/internal/Phase.scala12
-rw-r--r--src/reflect/scala/reflect/internal/Positions.scala278
-rw-r--r--src/reflect/scala/reflect/internal/Precedence.scala38
-rw-r--r--src/reflect/scala/reflect/internal/Printers.scala1020
-rw-r--r--src/reflect/scala/reflect/internal/PrivateWithin.scala27
-rw-r--r--src/reflect/scala/reflect/internal/ReificationSupport.scala1146
-rw-r--r--src/reflect/scala/reflect/internal/Required.scala11
-rw-r--r--src/reflect/scala/reflect/internal/Scopes.scala210
-rw-r--r--src/reflect/scala/reflect/internal/StdAttachments.scala61
-rw-r--r--src/reflect/scala/reflect/internal/StdCreators.scala3
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala613
-rw-r--r--src/reflect/scala/reflect/internal/SymbolPairs.scala302
-rw-r--r--src/reflect/scala/reflect/internal/SymbolTable.scala157
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala1313
-rw-r--r--src/reflect/scala/reflect/internal/TreeGen.scala709
-rw-r--r--src/reflect/scala/reflect/internal/TreeInfo.scala395
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala696
-rw-r--r--src/reflect/scala/reflect/internal/TypeDebugging.scala126
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala4628
-rw-r--r--src/reflect/scala/reflect/internal/Variance.scala90
-rw-r--r--src/reflect/scala/reflect/internal/Variances.scala218
-rw-r--r--src/reflect/scala/reflect/internal/annotations/compileTimeOnly.scala31
-rw-r--r--src/reflect/scala/reflect/internal/annotations/package.scala6
-rw-r--r--src/reflect/scala/reflect/internal/pickling/ByteCodecs.scala19
-rw-r--r--src/reflect/scala/reflect/internal/pickling/PickleBuffer.scala31
-rw-r--r--src/reflect/scala/reflect/internal/pickling/PickleFormat.scala8
-rw-r--r--src/reflect/scala/reflect/internal/pickling/Translations.scala129
-rw-r--r--src/reflect/scala/reflect/internal/pickling/UnPickler.scala594
-rw-r--r--src/reflect/scala/reflect/internal/settings/AbsSettings.scala3
-rw-r--r--src/reflect/scala/reflect/internal/settings/MutableSettings.scala36
-rw-r--r--src/reflect/scala/reflect/internal/tpe/CommonOwners.scala51
-rw-r--r--src/reflect/scala/reflect/internal/tpe/FindMembers.scala288
-rw-r--r--src/reflect/scala/reflect/internal/tpe/GlbLubs.scala611
-rw-r--r--src/reflect/scala/reflect/internal/tpe/TypeComparers.scala592
-rw-r--r--src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala275
-rw-r--r--src/reflect/scala/reflect/internal/tpe/TypeMaps.scala1173
-rw-r--r--src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala48
-rw-r--r--src/reflect/scala/reflect/internal/transform/Erasure.scala100
-rw-r--r--src/reflect/scala/reflect/internal/transform/PostErasure.scala19
-rw-r--r--src/reflect/scala/reflect/internal/transform/RefChecks.scala5
-rw-r--r--src/reflect/scala/reflect/internal/transform/Transforms.scala14
-rw-r--r--src/reflect/scala/reflect/internal/transform/UnCurry.scala13
-rw-r--r--src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala122
-rw-r--r--src/reflect/scala/reflect/internal/util/Collections.scala106
-rw-r--r--src/reflect/scala/reflect/internal/util/FreshNameCreator.scala28
-rw-r--r--src/reflect/scala/reflect/internal/util/HashSet.scala6
-rw-r--r--src/reflect/scala/reflect/internal/util/Origins.scala5
-rw-r--r--src/reflect/scala/reflect/internal/util/Position.scala476
-rw-r--r--src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala124
-rw-r--r--src/reflect/scala/reflect/internal/util/Set.scala6
-rw-r--r--src/reflect/scala/reflect/internal/util/SourceFile.scala77
-rw-r--r--src/reflect/scala/reflect/internal/util/Statistics.scala22
-rw-r--r--src/reflect/scala/reflect/internal/util/StringOps.scala59
-rw-r--r--src/reflect/scala/reflect/internal/util/StripMarginInterpolator.scala5
-rw-r--r--src/reflect/scala/reflect/internal/util/TableDef.scala37
-rw-r--r--src/reflect/scala/reflect/internal/util/ThreeValues.scala3
-rw-r--r--src/reflect/scala/reflect/internal/util/TraceSymbolActivity.scala52
-rw-r--r--src/reflect/scala/reflect/internal/util/TriState.scala28
-rw-r--r--src/reflect/scala/reflect/internal/util/WeakHashSet.scala56
-rw-r--r--src/reflect/scala/reflect/internal/util/package.scala37
-rw-r--r--src/reflect/scala/reflect/io/AbstractFile.scala93
-rw-r--r--src/reflect/scala/reflect/io/Directory.scala18
-rw-r--r--src/reflect/scala/reflect/io/File.scala95
-rw-r--r--src/reflect/scala/reflect/io/FileOperationException.scala3
-rw-r--r--src/reflect/scala/reflect/io/IOStats.scala32
-rw-r--r--src/reflect/scala/reflect/io/NoAbstractFile.scala10
-rw-r--r--src/reflect/scala/reflect/io/Path.scala88
-rw-r--r--src/reflect/scala/reflect/io/PlainFile.scala33
-rw-r--r--src/reflect/scala/reflect/io/Streamable.scala22
-rw-r--r--src/reflect/scala/reflect/io/VirtualDirectory.scala20
-rw-r--r--src/reflect/scala/reflect/io/VirtualFile.scala43
-rw-r--r--src/reflect/scala/reflect/io/ZipArchive.scala100
-rw-r--r--src/reflect/scala/reflect/macros/Aliases.scala22
-rw-r--r--src/reflect/scala/reflect/macros/Attachments.scala12
-rw-r--r--src/reflect/scala/reflect/macros/Enclosures.scala104
-rw-r--r--src/reflect/scala/reflect/macros/Evals.scala15
-rw-r--r--src/reflect/scala/reflect/macros/ExprUtils.scala20
-rw-r--r--src/reflect/scala/reflect/macros/FrontEnds.scala9
-rw-r--r--src/reflect/scala/reflect/macros/Infrastructure.scala9
-rw-r--r--src/reflect/scala/reflect/macros/Internals.scala79
-rw-r--r--src/reflect/scala/reflect/macros/Names.scala51
-rw-r--r--src/reflect/scala/reflect/macros/Parsers.scala9
-rw-r--r--src/reflect/scala/reflect/macros/Reifiers.scala33
-rw-r--r--src/reflect/scala/reflect/macros/TreeBuilder.scala72
-rw-r--r--src/reflect/scala/reflect/macros/Typers.scala93
-rw-r--r--src/reflect/scala/reflect/macros/Universe.scala500
-rw-r--r--src/reflect/scala/reflect/macros/blackbox/Context.scala (renamed from src/reflect/scala/reflect/macros/Context.scala)23
-rw-r--r--src/reflect/scala/reflect/macros/package.scala17
-rw-r--r--src/reflect/scala/reflect/macros/whitebox/Context.scala77
-rw-r--r--src/reflect/scala/reflect/runtime/Gil.scala25
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala655
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverse.scala125
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala448
-rw-r--r--src/reflect/scala/reflect/runtime/ReflectSetup.scala5
-rw-r--r--src/reflect/scala/reflect/runtime/ReflectionUtils.scala95
-rw-r--r--src/reflect/scala/reflect/runtime/Settings.scala13
-rw-r--r--src/reflect/scala/reflect/runtime/SymbolLoaders.scala109
-rw-r--r--src/reflect/scala/reflect/runtime/SymbolTable.scala24
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedOps.scala64
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala222
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedTypes.scala87
-rw-r--r--src/reflect/scala/reflect/runtime/ThreadLocalStorage.scala28
-rw-r--r--src/reflect/scala/reflect/runtime/TwoWayCache.scala15
-rw-r--r--src/reflect/scala/reflect/runtime/TwoWayCaches.scala68
-rw-r--r--src/reflect/scala/reflect/runtime/package.scala12
162 files changed, 18560 insertions, 10219 deletions
diff --git a/src/reflect/scala/reflect/api/Annotations.scala b/src/reflect/scala/reflect/api/Annotations.scala
index 09eaf7afb4..b880fad756 100644
--- a/src/reflect/scala/reflect/api/Annotations.scala
+++ b/src/reflect/scala/reflect/api/Annotations.scala
@@ -1,14 +1,15 @@
-package scala.reflect
+package scala
+package reflect
package api
import scala.collection.immutable.ListMap
/**
- * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
+ * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * This trait provides annotation support for the reflection API.
+ * This trait provides annotation support for the reflection API.
*
- * The API distinguishes between two kinds of annotations:
+ * In Scala, annotations belong to one of the two categories:
*
* <ul>
* <li>''Java annotations'': annotations on definitions produced by the Java compiler, i.e., subtypes of [[java.lang.annotation.Annotation]]
@@ -21,16 +22,13 @@ import scala.collection.immutable.ListMap
* it is stored as special attributes in the corresponding classfile, and not as a Java annotation. Note that subclassing
* just [[scala.annotation.Annotation]] is not enough to have the corresponding metadata persisted for runtime reflection.
*
- * The distinction between Java and Scala annotations is manifested in the contract of [[scala.reflect.api.Annotations#Annotation]], which exposes
- * both `scalaArgs` and `javaArgs`. For Scala or Java annotations extending [[scala.annotation.ClassfileAnnotation]] `scalaArgs` is empty
- * and arguments are stored in `javaArgs`. For all other Scala annotations, arguments are stored in `scalaArgs` and `javaArgs` is empty.
+ * Both Java and Scala annotations are represented as typed trees carrying constructor invocations corresponding
+ * to the annotation. For instance, the annotation in `@ann(1, 2) class C` is represented as `q"@new ann(1, 2)"`.
*
- * Arguments in `scalaArgs` are represented as typed trees. Note that these trees are not transformed by any phases
- * following the type-checker. Arguments in `javaArgs` are repesented as a map from [[scala.reflect.api.Names#Name]] to
- * [[scala.reflect.api.Annotations#JavaArgument]]. Instances of `JavaArgument` represent different kinds of Java annotation arguments:
- * - literals (primitive and string constants),
- * - arrays and
- * - nested annotations.
+ * Unlike Java reflection, Scala reflection does not support evaluation of constructor invocations stored in annotations
+ * into underlying objects. For instance it's impossible to go from `@ann(1, 2) class C` to `ann(1, 2)`, so one
+ * has to analyze trees representing annotation arguments to manually extract corresponding values. Towards that end,
+ * arguments of an annotation can be obtained via `annotation.tree.children.tail`.
*
* For more information about `Annotation`s, see the [[http://docs.scala-lang.org/overviews/reflection/annotations-names-scopes.html Reflection Guide: Annotations, Names, Scopes, and More]]
*
@@ -45,23 +43,22 @@ trait Annotations { self: Universe =>
*/
type Annotation >: Null <: AnyRef with AnnotationApi
- /** A tag that preserves the identity of the `Annotation` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
+ /** The constructor/extractor for `Annotation` instances.
+ * @group Extractors
*/
- implicit val AnnotationTag: ClassTag[Annotation]
-
- /** The constructor/extractor for `Annotation` instances.
- * @group Extractors
- */
- val Annotation: AnnotationExtractor
+ val Annotation: AnnotationExtractor
/** An extractor class to create and pattern match with syntax `Annotation(tpe, scalaArgs, javaArgs)`.
* Here, `tpe` is the annotation type, `scalaArgs` the payload of Scala annotations, and `javaArgs` the payload of Java annotations.
* @group Extractors
*/
abstract class AnnotationExtractor {
+ def apply(tree: Tree): Annotation = treeToAnnotation(tree)
+
+ @deprecated("Use `apply(tree: Tree): Annotation` instead", "2.11.0")
def apply(tpe: Type, scalaArgs: List[Tree], javaArgs: ListMap[Name, JavaArgument]): Annotation
+
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
def unapply(ann: Annotation): Option[(Type, List[Tree], ListMap[Name, JavaArgument])]
}
@@ -70,55 +67,64 @@ trait Annotations { self: Universe =>
* @group API
*/
trait AnnotationApi {
+ /** The tree underlying the annotation. */
+ def tree: Tree = annotationToTree(this.asInstanceOf[Annotation])
+
/** The type of the annotation. */
+ @deprecated("Use `tree.tpe` instead", "2.11.0")
def tpe: Type
/** Payload of the Scala annotation: a list of abstract syntax trees that represent the argument.
* Empty for Java annotations.
*/
+ @deprecated("Use `tree.children.tail` instead", "2.11.0")
def scalaArgs: List[Tree]
/** Payload of the Java annotation: a list of name-value pairs.
* Empty for Scala annotations.
*/
+ @deprecated("Use `tree.children.tail` instead", "2.11.0")
def javaArgs: ListMap[Name, JavaArgument]
}
+ protected[scala] def annotationToTree(ann: Annotation): Tree
+ protected[scala] def treeToAnnotation(tree: Tree): Annotation
+
/** A Java annotation argument
* @template
* @group Annotations
*/
- type JavaArgument >: Null <: AnyRef
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
+ type JavaArgument >: Null <: AnyRef with JavaArgumentApi
- /** A tag that preserves the identity of the `JavaArgument` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
+ /** Has no special methods. Is here to provides erased identity for `CompoundType`.
+ * @group API
*/
- implicit val JavaArgumentTag: ClassTag[JavaArgument]
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
+ trait JavaArgumentApi
/** A literal argument to a Java annotation as `"Use X instead"` in `@Deprecated("Use X instead")`
* @template
* @group Annotations
*/
- type LiteralArgument >: Null <: AnyRef with JavaArgument with LiteralArgumentApi
-
- /** A tag that preserves the identity of the `LiteralArgument` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val LiteralArgumentTag: ClassTag[LiteralArgument]
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
+ type LiteralArgument >: Null <: LiteralArgumentApi with JavaArgument
/** The constructor/extractor for `LiteralArgument` instances.
* @group Extractors
*/
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
val LiteralArgument: LiteralArgumentExtractor
/** An extractor class to create and pattern match with syntax `LiteralArgument(value)`
* where `value` is the constant argument.
* @group Extractors
*/
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
abstract class LiteralArgumentExtractor {
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
def apply(value: Constant): LiteralArgument
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
def unapply(arg: LiteralArgument): Option[Constant]
}
@@ -126,8 +132,10 @@ trait Annotations { self: Universe =>
* The main source of information about annotations is the [[scala.reflect.api.Annotations]] page.
* @group API
*/
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
trait LiteralArgumentApi {
/** The underlying compile-time constant value. */
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
def value: Constant
}
@@ -135,25 +143,24 @@ trait Annotations { self: Universe =>
* @template
* @group Annotations
*/
- type ArrayArgument >: Null <: AnyRef with JavaArgument with ArrayArgumentApi
-
- /** A tag that preserves the identity of the `ArrayArgument` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ArrayArgumentTag: ClassTag[ArrayArgument]
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
+ type ArrayArgument >: Null <: ArrayArgumentApi with JavaArgument
/** The constructor/extractor for `ArrayArgument` instances.
* @group Extractors
*/
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
val ArrayArgument: ArrayArgumentExtractor
/** An extractor class to create and pattern match with syntax `ArrayArgument(args)`
* where `args` is the argument array.
* @group Extractors
*/
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
abstract class ArrayArgumentExtractor {
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
def apply(args: Array[JavaArgument]): ArrayArgument
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
def unapply(arg: ArrayArgument): Option[Array[JavaArgument]]
}
@@ -161,8 +168,10 @@ trait Annotations { self: Universe =>
* The main source of information about annotations is the [[scala.reflect.api.Annotations]] page.
* @group API
*/
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
trait ArrayArgumentApi {
/** The underlying array of Java annotation arguments. */
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
def args: Array[JavaArgument]
}
@@ -170,25 +179,24 @@ trait Annotations { self: Universe =>
* @template
* @group Annotations
*/
- type NestedArgument >: Null <: AnyRef with JavaArgument with NestedArgumentApi
-
- /** A tag that preserves the identity of the `NestedArgument` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val NestedArgumentTag: ClassTag[NestedArgument]
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
+ type NestedArgument >: Null <: NestedArgumentApi with JavaArgument
/** The constructor/extractor for `NestedArgument` instances.
* @group Extractors
*/
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
val NestedArgument: NestedArgumentExtractor
/** An extractor class to create and pattern match with syntax `NestedArgument(annotation)`
* where `annotation` is the nested annotation.
* @group Extractors
*/
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
abstract class NestedArgumentExtractor {
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
def apply(annotation: Annotation): NestedArgument
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
def unapply(arg: NestedArgument): Option[Annotation]
}
@@ -196,8 +204,10 @@ trait Annotations { self: Universe =>
* The main source of information about annotations is the [[scala.reflect.api.Annotations]] page.
* @group API
*/
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
trait NestedArgumentApi {
/** The underlying nested annotation. */
+ @deprecated("Use `Annotation.tree` to inspect annotation arguments", "2.11.0")
def annotation: Annotation
}
-} \ No newline at end of file
+}
diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala
deleted file mode 100644
index 0c8e81a220..0000000000
--- a/src/reflect/scala/reflect/api/BuildUtils.scala
+++ /dev/null
@@ -1,78 +0,0 @@
-package scala.reflect
-package api
-
-/**
- * This is an internal implementation class.
- * @groupname TreeBuilders Tree Building
- */
-private[reflect] trait BuildUtils { self: Universe =>
-
- /** @group TreeBuilders */
- val build: BuildApi
-
- // this API abstracts away the functionality necessary for reification
- // it's too gimmicky and unstructured to be exposed directly in the universe
- // but we need it in a publicly available place for reification to work
-
- /** @group TreeBuilders */
- abstract class BuildApi {
- /** Selects type symbol with given simple name `name` from the defined members of `owner`.
- */
- def selectType(owner: Symbol, name: String): TypeSymbol
-
- /** Selects term symbol with given name and type from the defined members of prefix type
- */
- def selectTerm(owner: Symbol, name: String): TermSymbol
-
- /** Selects overloaded method symbol with given name and index
- */
- def selectOverloadedMethod(owner: Symbol, name: String, index: Int): MethodSymbol
-
- /** A fresh symbol with given name `name`, position `pos` and flags `flags` that has
- * the current symbol as its owner.
- */
- def newNestedSymbol(owner: Symbol, name: Name, pos: Position, flags: FlagSet, isClass: Boolean): Symbol
-
- /** Create a fresh free term symbol.
- * @param name the name of the free variable
- * @param value the value of the free variable at runtime
- * @param flags (optional) flags of the free variable
- * @param origin debug information that tells where this symbol comes from
- */
- def newFreeTerm(name: String, value: => Any, flags: FlagSet = NoFlags, origin: String = null): FreeTermSymbol
-
- /** Create a fresh free type symbol.
- * @param name the name of the free variable
- * @param flags (optional) flags of the free variable
- * @param origin debug information that tells where this symbol comes from
- */
- def newFreeType(name: String, flags: FlagSet = NoFlags, origin: String = null): FreeTypeSymbol
-
- /** Set symbol's type signature to given type.
- * @return the symbol itself
- */
- def setTypeSignature[S <: Symbol](sym: S, tpe: Type): S
-
- /** Set symbol's annotations to given annotations `annots`.
- */
- def setAnnotations[S <: Symbol](sym: S, annots: List[Annotation]): S
-
- def flagsFromBits(bits: Long): FlagSet
-
- def emptyValDef: ValDef
-
- def This(sym: Symbol): Tree
-
- def Select(qualifier: Tree, sym: Symbol): Select
-
- def Ident(sym: Symbol): Ident
-
- def TypeTree(tp: Type): TypeTree
-
- def thisPrefix(sym: Symbol): Type
-
- def setType[T <: Tree](tree: T, tpe: Type): T
-
- def setSymbol[T <: Tree](tree: T, sym: Symbol): T
- }
-}
diff --git a/src/reflect/scala/reflect/api/Constants.scala b/src/reflect/scala/reflect/api/Constants.scala
index f3d75c3c00..e73c5ffa91 100644
--- a/src/reflect/scala/reflect/api/Constants.scala
+++ b/src/reflect/scala/reflect/api/Constants.scala
@@ -3,7 +3,8 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package api
/**
@@ -68,7 +69,7 @@ package api
* val enumRef = jarg("enumRef").symbolValue
* println(enumRef) // value BAR
*
- * val siblings = enumRef.owner.typeSignature.declarations
+ * val siblings = enumRef.owner.info.decls
* val enumValues = siblings.filter(sym => sym.isVal && sym.isPublic)
* println(enumValues) // Scope{
* // final val FOO: JavaSimpleEnumeration;
@@ -164,7 +165,7 @@ trait Constants {
* // ideally one should match instead of casting
* println(enumRef) // value BAR
*
- * val siblings = enumRef.owner.typeSignature.declarations
+ * val siblings = enumRef.owner.info.decls
* val enumValues = siblings.filter(sym => sym.isVal && sym.isPublic)
* println(enumValues) // Scope{
* // final val FOO: JavaSimpleEnumeration;
@@ -183,12 +184,6 @@ trait Constants {
*/
type Constant >: Null <: AnyRef with ConstantApi
- /** A tag that preserves the identity of the `Constant` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ConstantTag: ClassTag[Constant]
-
/** The constructor/extractor for `Constant` instances.
* @group Extractors
*/
diff --git a/src/reflect/scala/reflect/api/Exprs.scala b/src/reflect/scala/reflect/api/Exprs.scala
index 2ba18a8207..5b6ff2325c 100644
--- a/src/reflect/scala/reflect/api/Exprs.scala
+++ b/src/reflect/scala/reflect/api/Exprs.scala
@@ -3,10 +3,12 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package api
import scala.reflect.runtime.{universe => ru}
+import scala.annotation.compileTimeOnly
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
@@ -90,7 +92,7 @@ trait Exprs { self: Universe =>
* }}}
* because expr of type Expr[T] itself does not have a method foo.
*/
- // @compileTimeOnly("Cannot use splice outside reify")
+ @compileTimeOnly("splice must be enclosed within a reify {} block")
def splice: T
/**
@@ -107,7 +109,7 @@ trait Exprs { self: Universe =>
* object Impls { def foo_impl(c: Context)(x: c.Expr[X]): c.Expr[x.value.T] = ... }
* }}}
*/
- // @compileTimeOnly("Cannot use value except for signatures of macro implementations")
+ @compileTimeOnly("cannot use value except for signatures of macro implementations")
val value: T
override def canEqual(x: Any) = x.isInstanceOf[Expr[_]]
@@ -174,4 +176,4 @@ private[scala] class SerializedExpr(var treec: TreeCreator, var tag: ru.WeakType
import ru._
Expr(rootMirror, treec)(tag)
}
-} \ No newline at end of file
+}
diff --git a/src/reflect/scala/reflect/api/FlagSets.scala b/src/reflect/scala/reflect/api/FlagSets.scala
index 4357aec9c9..bf4d6353df 100644
--- a/src/reflect/scala/reflect/api/FlagSets.scala
+++ b/src/reflect/scala/reflect/api/FlagSets.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package api
import scala.language.implicitConversions
@@ -61,12 +62,6 @@ trait FlagSets { self: Universe =>
*/
type FlagSet
- /** A tag that preserves the identity of the `FlagSet` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val FlagSetTag: ClassTag[FlagSet]
-
/** The API of `FlagSet` instances.
* The main source of information about flag sets is the [[scala.reflect.api.FlagSets]] page.
* @group Flags
@@ -136,8 +131,8 @@ trait FlagSets { self: Universe =>
/** Flag indicating that tree has `protected` modifier set */
val PROTECTED: FlagSet
- /** Flag indicating that tree represents a member local to current class
- * (i.e. private[this] or protected[this].
+ /** Flag indicating that tree represents a member local to current class,
+ * i.e. private[this] or protected[this].
* This requires having either PRIVATE or PROTECTED set as well.
*/
val LOCAL: FlagSet
@@ -171,6 +166,90 @@ trait FlagSets { self: Universe =>
/** Flag indicating that tree represents a variable or a member initialized to the default value */
val DEFAULTINIT: FlagSet
+
+ /** Flag indicating that tree represents an enum.
+ *
+ * It can only appear at
+ * - the enum's class
+ * - enum constants
+ **/
+ val ENUM: FlagSet
+
+ /** Flag indicating that tree represents a parameter of the primary constructor of some class
+ * or a synthetic member underlying thereof. E.g. here's how 'class C(val x: Int)' is represented:
+ *
+ * [[syntax trees at end of parser]]// Scala source: tmposDU52
+ * class C extends scala.AnyRef {
+ * <paramaccessor> val x: Int = _;
+ * def <init>(x: Int) = {
+ * super.<init>();
+ * ()
+ * }
+ * }
+ * ClassDef(
+ * Modifiers(), TypeName("C"), List(),
+ * Template(
+ * List(Select(Ident(scala), TypeName("AnyRef"))),
+ * noSelfType,
+ * List(
+ * ValDef(Modifiers(PARAMACCESSOR), TermName("x"), Ident(TypeName("Int")), EmptyTree),
+ * DefDef(
+ * Modifiers(), nme.CONSTRUCTOR, List(),
+ * List(List(ValDef(Modifiers(PARAM | PARAMACCESSOR), TermName("x"), Ident(TypeName("Int")), EmptyTree))), TypeTree(),
+ * Block(List(pendingSuperCall), Literal(Constant(())))))))))
+ */
+ val PARAMACCESSOR: FlagSet
+
+ /** Flag indicating that tree represents a parameter of the primary constructor of some case class
+ * or a synthetic member underlying thereof. E.g. here's how 'case class C(val x: Int)' is represented:
+ *
+ * [[syntax trees at end of parser]]// Scala source: tmpnHkJ3y
+ * case class C extends scala.Product with scala.Serializable {
+ * <caseaccessor> <paramaccessor> val x: Int = _;
+ * def <init>(x: Int) = {
+ * super.<init>();
+ * ()
+ * }
+ * }
+ * ClassDef(
+ * Modifiers(CASE), TypeName("C"), List(),
+ * Template(
+ * List(Select(Ident(scala), TypeName("Product")), Select(Ident(scala), TypeName("Serializable"))),
+ * noSelfType,
+ * List(
+ * ValDef(Modifiers(CASEACCESSOR | PARAMACCESSOR), TermName("x"), Ident(TypeName("Int")), EmptyTree),
+ * DefDef(
+ * Modifiers(), nme.CONSTRUCTOR, List(),
+ * List(List(ValDef(Modifiers(PARAM | PARAMACCESSOR), TermName("x"), Ident(TypeName("Int")), EmptyTree))), TypeTree(),
+ * Block(List(pendingSuperCall), Literal(Constant(())))))))))
+ */
+ val CASEACCESSOR: FlagSet
+
+ /** Flag used to distinguish programmatically generated definitions from user-written ones.
+ * @see ARTIFACT
+ */
+ val SYNTHETIC: FlagSet
+
+ /** Flag used to distinguish platform-specific implementation details.
+ * Trees and symbols which are currently marked ARTIFACT by scalac:
+ * * $outer fields and accessors
+ * * super accessors
+ * * protected accessors
+ * * lazy local accessors
+ * * bridge methods
+ * * default argument getters
+ * * evaluation-order preserving locals for right-associative and out-of-order named arguments
+ * * catch-expression storing vals
+ * * anything else which feels a setFlag(ARTIFACT)
+ *
+ * @see SYNTHETIC
+ */
+ val ARTIFACT: FlagSet
+
+ /** Flag that indicates methods that are supposed to be stable
+ * (e.g. synthetic getters of valdefs).
+ */
+ val STABLE: FlagSet
}
/** The empty set of flags
diff --git a/src/reflect/scala/reflect/api/ImplicitTags.scala b/src/reflect/scala/reflect/api/ImplicitTags.scala
new file mode 100644
index 0000000000..aca0692d0d
--- /dev/null
+++ b/src/reflect/scala/reflect/api/ImplicitTags.scala
@@ -0,0 +1,119 @@
+package scala
+package reflect
+package api
+
+/** Tags which preserve the identity of abstract types in the face of erasure.
+ * Can be used for pattern matching, instance tests, serialization and the like.
+ * @group Tags
+ */
+trait ImplicitTags {
+ self: Universe =>
+
+ // Tags for Types.
+ implicit val AnnotatedTypeTag: ClassTag[AnnotatedType]
+ implicit val BoundedWildcardTypeTag: ClassTag[BoundedWildcardType]
+ implicit val ClassInfoTypeTag: ClassTag[ClassInfoType]
+ implicit val CompoundTypeTag: ClassTag[CompoundType]
+ implicit val ConstantTypeTag: ClassTag[ConstantType]
+ implicit val ExistentialTypeTag: ClassTag[ExistentialType]
+ implicit val MethodTypeTag: ClassTag[MethodType]
+ implicit val NullaryMethodTypeTag: ClassTag[NullaryMethodType]
+ implicit val PolyTypeTag: ClassTag[PolyType]
+ implicit val RefinedTypeTag: ClassTag[RefinedType]
+ implicit val SingleTypeTag: ClassTag[SingleType]
+ implicit val SingletonTypeTag: ClassTag[SingletonType]
+ implicit val SuperTypeTag: ClassTag[SuperType]
+ implicit val ThisTypeTag: ClassTag[ThisType]
+ implicit val TypeBoundsTag: ClassTag[TypeBounds]
+ implicit val TypeRefTag: ClassTag[TypeRef]
+ implicit val TypeTagg: ClassTag[Type]
+
+ // Tags for Names.
+ implicit val NameTag: ClassTag[Name]
+ implicit val TermNameTag: ClassTag[TermName]
+ implicit val TypeNameTag: ClassTag[TypeName]
+
+ // Tags for Scopes.
+ implicit val ScopeTag: ClassTag[Scope]
+ implicit val MemberScopeTag: ClassTag[MemberScope]
+
+ // Tags for Annotations.
+ implicit val AnnotationTag: ClassTag[Annotation]
+ implicit val JavaArgumentTag: ClassTag[JavaArgument]
+ implicit val LiteralArgumentTag: ClassTag[LiteralArgument]
+ implicit val ArrayArgumentTag: ClassTag[ArrayArgument]
+ implicit val NestedArgumentTag: ClassTag[NestedArgument]
+
+ // Tags for Symbols.
+ implicit val TermSymbolTag: ClassTag[TermSymbol]
+ implicit val MethodSymbolTag: ClassTag[MethodSymbol]
+ implicit val SymbolTag: ClassTag[Symbol]
+ implicit val TypeSymbolTag: ClassTag[TypeSymbol]
+ implicit val ModuleSymbolTag: ClassTag[ModuleSymbol]
+ implicit val ClassSymbolTag: ClassTag[ClassSymbol]
+
+ // Tags for misc Tree relatives.
+ implicit val PositionTag: ClassTag[Position]
+ implicit val ConstantTag: ClassTag[Constant]
+ implicit val FlagSetTag: ClassTag[FlagSet]
+ implicit val ModifiersTag: ClassTag[Modifiers]
+
+ // Tags for Trees. WTF.
+ implicit val AlternativeTag: ClassTag[Alternative]
+ implicit val AnnotatedTag: ClassTag[Annotated]
+ implicit val AppliedTypeTreeTag: ClassTag[AppliedTypeTree]
+ implicit val ApplyTag: ClassTag[Apply]
+ implicit val AssignOrNamedArgTag: ClassTag[AssignOrNamedArg]
+ implicit val AssignTag: ClassTag[Assign]
+ implicit val BindTag: ClassTag[Bind]
+ implicit val BlockTag: ClassTag[Block]
+ implicit val CaseDefTag: ClassTag[CaseDef]
+ implicit val ClassDefTag: ClassTag[ClassDef]
+ implicit val CompoundTypeTreeTag: ClassTag[CompoundTypeTree]
+ implicit val DefDefTag: ClassTag[DefDef]
+ implicit val DefTreeTag: ClassTag[DefTree]
+ implicit val ExistentialTypeTreeTag: ClassTag[ExistentialTypeTree]
+ implicit val FunctionTag: ClassTag[Function]
+ implicit val GenericApplyTag: ClassTag[GenericApply]
+ implicit val IdentTag: ClassTag[Ident]
+ implicit val IfTag: ClassTag[If]
+ implicit val ImplDefTag: ClassTag[ImplDef]
+ implicit val ImportSelectorTag: ClassTag[ImportSelector]
+ implicit val ImportTag: ClassTag[Import]
+ implicit val LabelDefTag: ClassTag[LabelDef]
+ implicit val LiteralTag: ClassTag[Literal]
+ implicit val MatchTag: ClassTag[Match]
+ implicit val MemberDefTag: ClassTag[MemberDef]
+ implicit val ModuleDefTag: ClassTag[ModuleDef]
+ implicit val NameTreeTag: ClassTag[NameTree]
+ implicit val NewTag: ClassTag[New]
+ implicit val PackageDefTag: ClassTag[PackageDef]
+ implicit val RefTreeTag: ClassTag[RefTree]
+ implicit val ReturnTag: ClassTag[Return]
+ implicit val SelectFromTypeTreeTag: ClassTag[SelectFromTypeTree]
+ implicit val SelectTag: ClassTag[Select]
+ implicit val SingletonTypeTreeTag: ClassTag[SingletonTypeTree]
+ implicit val StarTag: ClassTag[Star]
+ implicit val SuperTag: ClassTag[Super]
+ implicit val SymTreeTag: ClassTag[SymTree]
+ implicit val TemplateTag: ClassTag[Template]
+ implicit val TermTreeTag: ClassTag[TermTree]
+ implicit val ThisTag: ClassTag[This]
+ implicit val ThrowTag: ClassTag[Throw]
+ implicit val TreeTag: ClassTag[Tree]
+ implicit val TryTag: ClassTag[Try]
+ implicit val TypTreeTag: ClassTag[TypTree]
+ implicit val TypeApplyTag: ClassTag[TypeApply]
+ implicit val TypeBoundsTreeTag: ClassTag[TypeBoundsTree]
+ implicit val TypeDefTag: ClassTag[TypeDef]
+ implicit val TypeTreeTag: ClassTag[TypeTree]
+ implicit val TypedTag: ClassTag[Typed]
+ implicit val UnApplyTag: ClassTag[UnApply]
+ implicit val ValDefTag: ClassTag[ValDef]
+ implicit val ValOrDefDefTag: ClassTag[ValOrDefDef]
+
+ // Miscellaneous
+ implicit val TreeCopierTag: ClassTag[TreeCopier]
+ implicit val RuntimeClassTag: ClassTag[RuntimeClass]
+ implicit val MirrorTag: ClassTag[Mirror]
+}
diff --git a/src/reflect/scala/reflect/api/Importers.scala b/src/reflect/scala/reflect/api/Importers.scala
deleted file mode 100644
index afc4f2f25d..0000000000
--- a/src/reflect/scala/reflect/api/Importers.scala
+++ /dev/null
@@ -1,103 +0,0 @@
-package scala.reflect
-package api
-
-/**
- * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
- *
- * This trait provides support for importers, a facility to migrate reflection artifacts between universes.
- * ''Note: this trait should typically be used only rarely.''
- *
- * Reflection artifacts, such as [[scala.reflect.api.Symbols Symbols]] and [[scala.reflect.api.Types Types]],
- * are contained in [[scala.reflect.api.Universes Universe]]s. Typically all processing happens
- * within a single `Universe` (e.g. a compile-time macro `Universe` or a runtime reflection `Universe`), but sometimes
- * there is a need to migrate artifacts from one `Universe` to another. For example, runtime compilation works by
- * importing runtime reflection trees into a runtime compiler universe, compiling the importees and exporting the
- * result back.
- *
- * Reflection artifacts are firmly grounded in their `Universe`s, which is reflected by the fact that types of artifacts
- * from different universes are not compatible. By using `Importer`s, however, they be imported from one universe
- * into another. For example, to import `foo.bar.Baz` from the source `Universe` to the target `Universe`,
- * an importer will first check whether the entire owner chain exists in the target `Universe`.
- * If it does, then nothing else will be done. Otherwise, the importer will recreate the entire owner chain
- * and will import the corresponding type signatures into the target `Universe`.
- *
- * Since importers match `Symbol` tables of the source and the target `Universe`s using plain string names,
- * it is programmer's responsibility to make sure that imports don't distort semantics, e.g., that
- * `foo.bar.Baz` in the source `Universe` means the same that `foo.bar.Baz` does in the target `Universe`.
- *
- * === Example ===
- *
- * Here's how one might implement a macro that performs compile-time evaluation of its argument
- * by using a runtime compiler to compile and evaluate a tree that belongs to a compile-time compiler:
- *
- * {{{
- * def staticEval[T](x: T) = macro staticEval[T]
- *
- * def staticEval[T](c: scala.reflect.macros.Context)(x: c.Expr[T]) = {
- * // creates a runtime reflection universe to host runtime compilation
- * import scala.reflect.runtime.{universe => ru}
- * val mirror = ru.runtimeMirror(c.libraryClassLoader)
- * import scala.tools.reflect.ToolBox
- * val toolBox = mirror.mkToolBox()
- *
- * // runtime reflection universe and compile-time macro universe are different
- * // therefore an importer is needed to bridge them
- * // currently mkImporter requires a cast to correctly assign the path-dependent types
- * val importer0 = ru.mkImporter(c.universe)
- * val importer = importer0.asInstanceOf[ru.Importer { val from: c.universe.type }]
- *
- * // the created importer is used to turn a compiler tree into a runtime compiler tree
- * // both compilers use the same classpath, so semantics remains intact
- * val imported = importer.importTree(tree)
- *
- * // after the tree is imported, it can be evaluated as usual
- * val tree = toolBox.resetAllAttrs(imported.duplicate)
- * val valueOfX = toolBox.eval(imported).asInstanceOf[T]
- * ...
- * }
- * }}}
- *
- * @group ReflectionAPI
- */
-trait Importers { self: Universe =>
-
- /** Creates an importer that moves reflection artifacts between universes.
- * @group Importers
- */
- def mkImporter(from0: Universe): Importer { val from: from0.type }
-
- /** The API of importers.
- * The main source of information about importers is the [[scala.reflect.api.Importers]] page.
- * @group Importers
- */
- trait Importer {
- /** The source universe of reflection artifacts that will be processed.
- * The target universe is universe that created this importer with `mkImporter`.
- */
- val from: Universe
-
- /** An importer that works in reverse direction, namely:
- * imports reflection artifacts from the current universe to the universe specified in `from`.
- */
- val reverse: from.Importer { val from: self.type }
-
- /** In the current universe, locates or creates a symbol that corresponds to the provided symbol in the source universe.
- * If necessary imports the owner chain, companions, type signature, annotations and attachments.
- */
- def importSymbol(sym: from.Symbol): Symbol
-
- /** In the current universe, locates or creates a type that corresponds to the provided type in the source universe.
- * If necessary imports the underlying symbols, annotations, scopes and trees.
- */
- def importType(tpe: from.Type): Type
-
- /** In the current universe, creates a tree that corresponds to the provided tree in the source universe.
- * If necessary imports the underlying symbols, types and attachments.
- */
- def importTree(tree: from.Tree): Tree
-
- /** In the current universe, creates a position that corresponds to the provided position in the source universe.
- */
- def importPosition(pos: from.Position): Position
- }
-} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/api/Internals.scala b/src/reflect/scala/reflect/api/Internals.scala
new file mode 100644
index 0000000000..577cd09295
--- /dev/null
+++ b/src/reflect/scala/reflect/api/Internals.scala
@@ -0,0 +1,1238 @@
+package scala
+package reflect
+package api
+
+import scala.language.implicitConversions
+import scala.language.higherKinds
+
+/**
+ * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
+ *
+ * This trait assembles APIs occasionally necessary for performing low-level operations on reflection artifacts.
+ * See [[Internals#InternalApi]] for more information about nature, usefulness and compatibility guarantees of these APIs.
+ *
+ * @group ReflectionAPI
+ */
+trait Internals { self: Universe =>
+
+ /** @see [[InternalApi]]
+ * @group Internal
+ */
+ val internal: Internal
+
+ /** @see [[InternalApi]]
+ * @group Internal
+ */
+ type Internal <: InternalApi
+
+ /** Reflection API exhibits a tension inherent to experimental things:
+ * on the one hand we want it to grow into a beautiful and robust API,
+ * but on the other hand we have to deal with immaturity of underlying mechanisms
+ * by providing not very pretty solutions to enable important use cases.
+ *
+ * In Scala 2.10, which was our first stab at reflection API, we didn't have a systematic
+ * approach to dealing with this tension, sometimes exposing too much of internals (e.g. Symbol.deSkolemize)
+ * and sometimes exposing too little (e.g. there's still no facility to change owners, to do typing
+ * transformations, etc). This resulted in certain confusion with some internal APIs
+ * living among public ones, scaring the newcomers, and some internal APIs only available via casting,
+ * which requires intimate knowledge of the compiler and breaks compatibility guarantees.
+ *
+ * This led to creation of the `internal` API module for the reflection API, which
+ * provides advanced APIs necessary for macros that push boundaries of the state of the art,
+ * clearly demarcating them from the more or less straightforward rest and
+ * providing compatibility guarantees on par with the rest of the reflection API
+ * (full compatibility within minor releases, best effort towards backward compatibility within major releases,
+ * clear replacement path in case of rare incompatible changes in major releases).
+ *
+ * The `internal` module itself (the value that implements [[InternalApi]]) isn't defined here,
+ * in [[scala.reflect.api.Universe]], but is provided on per-implementation basis. Runtime API endpoint
+ * ([[scala.reflect.runtime.universe]]) provides `universe.compat: InternalApi`, whereas compile-time API endpoints
+ * (instances of [[scala.reflect.macros.Context]]) provide `c.compat: ContextInternalApi`, which extends `InternalApi`
+ * with additional universe-specific and context-specific functionality.
+ *
+ * @group Internal
+ */
+ trait InternalApi { internal =>
+ /** This is an internal implementation module.
+ */
+ val reificationSupport: ReificationSupportApi
+
+ /** Creates an importer that moves reflection artifacts between universes.
+ * @see [[Importer]]
+ */
+ // SI-6241: move importers to a mirror
+ def createImporter(from0: Universe): Importer { val from: from0.type }
+
+ /**
+ * Convert a [[scala.reflect.api.TypeTags#TypeTag]] to a [[scala.reflect.Manifest]].
+ *
+ * Compiler usually generates these conversions automatically, when a type tag for a type `T` is in scope,
+ * and an implicit of type `Manifest[T]` is requested, but this method can also be called manually.
+ * For example:
+ * {{{
+ * typeTagToManifest(scala.reflect.runtime.currentMirror, implicitly[TypeTag[String]])
+ * }}}
+ * @group TagInterop
+ */
+ def typeTagToManifest[T: ClassTag](mirror: Any, tag: Universe#TypeTag[T]): Manifest[T] =
+ throw new UnsupportedOperationException("This universe does not support tag -> manifest conversions. Use a JavaUniverse, e.g. the scala.reflect.runtime.universe.")
+
+ /**
+ * Convert a [[scala.reflect.Manifest]] to a [[scala.reflect.api.TypeTags#TypeTag]].
+ *
+ * Compiler usually generates these conversions automatically, when a manifest for a type `T` is in scope,
+ * and an implicit of type `TypeTag[T]` is requested, but this method can also be called manually.
+ * For example:
+ * {{{
+ * manifestToTypeTag(scala.reflect.runtime.currentMirror, implicitly[Manifest[String]])
+ * }}}
+ * @group TagInterop
+ */
+ def manifestToTypeTag[T](mirror: Any, manifest: Manifest[T]): Universe#TypeTag[T] =
+ throw new UnsupportedOperationException("This universe does not support manifest -> tag conversions. Use a JavaUniverse, e.g. the scala.reflect.runtime.universe.")
+
+ /** Create a new scope with the given initial elements.
+ */
+ def newScopeWith(elems: Symbol*): Scope
+
+ /** Extracts free term symbols from a tree that is reified or contains reified subtrees.
+ */
+ def freeTerms(tree: Tree): List[FreeTermSymbol]
+
+ /** Extracts free type symbols from a tree that is reified or contains reified subtrees.
+ */
+ def freeTypes(tree: Tree): List[FreeTypeSymbol]
+
+ /** Substitute symbols in `to` for corresponding occurrences of references to
+ * symbols `from` in this type.
+ */
+ def substituteSymbols(tree: Tree, from: List[Symbol], to: List[Symbol]): Tree
+
+ /** Substitute types in `to` for corresponding occurrences of references to
+ * symbols `from` in this tree.
+ */
+ def substituteTypes(tree: Tree, 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(tree: Tree, clazz: Symbol, to: Tree): Tree
+
+ /** A factory method for `ClassDef` nodes.
+ */
+ def classDef(sym: Symbol, impl: Template): ClassDef
+
+ /** A factory method for `ModuleDef` nodes.
+ */
+ def moduleDef(sym: Symbol, impl: Template): ModuleDef
+
+ /** A factory method for `ValDef` nodes.
+ */
+ def valDef(sym: Symbol, rhs: Tree): ValDef
+
+ /** A factory method for `ValDef` nodes.
+ */
+ def valDef(sym: Symbol): ValDef
+
+ /** A factory method for `DefDef` nodes.
+ */
+ def defDef(sym: Symbol, mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree): DefDef
+
+ /** A factory method for `DefDef` nodes.
+ */
+ def defDef(sym: Symbol, vparamss: List[List[ValDef]], rhs: Tree): DefDef
+
+ /** A factory method for `DefDef` nodes.
+ */
+ def defDef(sym: Symbol, mods: Modifiers, rhs: Tree): DefDef
+
+ /** A factory method for `DefDef` nodes.
+ */
+ def defDef(sym: Symbol, rhs: Tree): DefDef
+
+ /** A factory method for `DefDef` nodes.
+ */
+ def defDef(sym: Symbol, rhs: List[List[Symbol]] => Tree): DefDef
+
+ /** A factory method for `TypeDef` nodes.
+ */
+ def typeDef(sym: Symbol, rhs: Tree): TypeDef
+
+ /** A factory method for `TypeDef` nodes.
+ */
+ def typeDef(sym: Symbol): TypeDef
+
+ /** A factory method for `LabelDef` nodes.
+ */
+ def labelDef(sym: Symbol, params: List[Symbol], rhs: Tree): LabelDef
+
+ /** Does this symbol represent a free term captured by reification?
+ * If yes, `isTerm` is also guaranteed to be true.
+ */
+ def isFreeTerm(symbol: Symbol): Boolean
+
+ /** This symbol cast to a free term symbol.
+ * @throws ScalaReflectionException if `isFreeTerm` is false.
+ */
+ def asFreeTerm(symbol: Symbol): FreeTermSymbol
+
+ /** Does this symbol represent a free type captured by reification?
+ * If yes, `isType` is also guaranteed to be true.
+ */
+ def isFreeType(symbol: Symbol): Boolean
+
+ /** This symbol cast to a free type symbol.
+ * @throws ScalaReflectionException if `isFreeType` is false.
+ */
+ def asFreeType(symbol: Symbol): FreeTypeSymbol
+
+ def newTermSymbol(owner: Symbol, name: TermName, pos: Position = NoPosition, flags: FlagSet = NoFlags): TermSymbol
+
+ def newModuleAndClassSymbol(owner: Symbol, name: Name, pos: Position = NoPosition, flags: FlagSet = NoFlags): (ModuleSymbol, ClassSymbol)
+
+ def newMethodSymbol(owner: Symbol, name: TermName, pos: Position = NoPosition, flags: FlagSet = NoFlags): MethodSymbol
+
+ def newTypeSymbol(owner: Symbol, name: TypeName, pos: Position = NoPosition, flags: FlagSet = NoFlags): TypeSymbol
+
+ def newClassSymbol(owner: Symbol, name: TypeName, pos: Position = NoPosition, flags: FlagSet = NoFlags): ClassSymbol
+
+ def newFreeTerm(name: String, value: => Any, flags: FlagSet = NoFlags, origin: String = null): FreeTermSymbol
+
+ def newFreeType(name: String, flags: FlagSet = NoFlags, origin: String = null): FreeTypeSymbol
+
+ /** Does this symbol or its underlying type represent a typechecking error?
+ */
+ def isErroneous(symbol: Symbol): Boolean
+
+ /** Does this symbol represent the definition of a skolem?
+ * Skolems are used during typechecking to represent type parameters viewed from inside their scopes.
+ */
+ def isSkolem(symbol: Symbol): Boolean
+
+ /** If this symbol is a skolem, its corresponding type parameter, otherwise the symbol itself.
+ *
+ * [[https://groups.google.com/forum/#!msg/scala-internals/0j8laVNTQsI/kRXMF_c8bGsJ To quote Martin Odersky]],
+ * skolems are synthetic type "constants" that are copies of existentially bound or universally
+ * bound type variables. E.g. if one is inside the right-hand side of a method:
+ *
+ * {{{
+ * def foo[T](x: T) = ... foo[List[T]]....
+ * }}}
+ *
+ * the skolem named `T` refers to the unknown type instance of `T` when `foo` is called. It needs to be different
+ * from the type parameter because in a recursive call as in the `foo[List[T]]` above the type parameter gets
+ * substituted with `List[T]`, but the ''type skolem'' stays what it is.
+ *
+ * The other form of skolem is an ''existential skolem''. Say one has a function
+ *
+ * {{{
+ * def bar(xs: List[T] forSome { type T }) = xs.head
+ * }}}
+ *
+ * then each occurrence of `xs` on the right will have type `List[T']` where `T'` is a fresh copy of `T`.
+ */
+ def deSkolemize(symbol: Symbol): Symbol
+
+ /** Forces all outstanding completers associated with this symbol.
+ * After this call returns, the symbol becomes immutable and thread-safe.
+ */
+ def initialize(symbol: Symbol): symbol.type
+
+ /** Calls [[initialize]] on the owner and all the value and type parameters of the symbol.
+ */
+ def fullyInitialize(symbol: Symbol): symbol.type
+
+ /** Calls [[initialize]] on all the value and type parameters of the type.
+ */
+ def fullyInitialize(tp: Type): tp.type
+
+ /** Calls [[initialize]] on all the symbols that the scope consists of.
+ */
+ def fullyInitialize(scope: Scope): scope.type
+
+ /** Returns internal flags associated with the symbol.
+ */
+ def flags(symbol: Symbol): FlagSet
+
+ /** A creator for `ThisType` types.
+ */
+ def thisType(sym: Symbol): Type
+
+ /** A creator for `SingleType` types.
+ */
+ def singleType(pre: Type, sym: Symbol): Type
+
+ /** A creator for `SuperType` types.
+ */
+ def superType(thistpe: Type, supertpe: Type): Type
+
+ /** A creator for `ConstantType` types.
+ */
+ def constantType(value: Constant): ConstantType
+
+ /** A creator for `TypeRef` types.
+ */
+ def typeRef(pre: Type, sym: Symbol, args: List[Type]): Type
+
+ /** A creator for `RefinedType` types.
+ */
+ def refinedType(parents: List[Type], decls: Scope): RefinedType
+
+ /** A creator for `RefinedType` types.
+ */
+ def refinedType(parents: List[Type], decls: Scope, clazz: Symbol): RefinedType
+
+ /** A creator for `RefinedType` types.
+ */
+ def refinedType(parents: List[Type], owner: Symbol): Type
+
+ /** A creator for `RefinedType` types.
+ */
+ def refinedType(parents: List[Type], owner: Symbol, decls: Scope): Type
+
+ /** A creator for `RefinedType` types.
+ */
+ def refinedType(parents: List[Type], owner: Symbol, decls: Scope, pos: Position): 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 `ClassInfoType` types.
+ */
+ def classInfoType(parents: List[Type], decls: Scope, typeSymbol: Symbol): ClassInfoType
+
+ /** A creator for `MethodType` types.
+ */
+ def methodType(params: List[Symbol], resultType: Type): MethodType
+
+ /** A creator for `NullaryMethodType` types.
+ */
+ def nullaryMethodType(resultType: Type): NullaryMethodType
+
+ /** 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): PolyType
+
+ /** A creator for `ExistentialType` types.
+ */
+ def existentialType(quantified: List[Symbol], underlying: Type): ExistentialType
+
+ /** 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`.
+ * @group TypeCreators
+ */
+ def existentialAbstraction(tparams: List[Symbol], tpe0: Type): Type
+
+ /** A creator for `AnnotatedType` types.
+ */
+ def annotatedType(annotations: List[Annotation], underlying: Type): AnnotatedType
+
+ /** A creator for `TypeBounds` types.
+ */
+ def typeBounds(lo: Type, hi: Type): TypeBounds
+
+ /** A creator for `BoundedWildcardType` types.
+ */
+ def boundedWildcardType(bounds: TypeBounds): BoundedWildcardType
+
+ /** Syntactic conveniences for additional internal APIs for trees, symbols and types */
+ type Decorators <: DecoratorApi
+
+ /** @see [[Decorators]] */
+ val decorators: Decorators
+
+ /** @see [[Decorators]] */
+ trait DecoratorApi {
+ /** Extension methods for trees */
+ type TreeDecorator[T <: Tree] <: TreeDecoratorApi[T]
+
+ /** @see [[TreeDecorator]] */
+ implicit def treeDecorator[T <: Tree](tree: T): TreeDecorator[T]
+
+ /** @see [[TreeDecorator]] */
+ class TreeDecoratorApi[T <: Tree](val tree: T) {
+ /** @see [[internal.freeTerms]] */
+ def freeTerms: List[FreeTermSymbol] = internal.freeTerms(tree)
+
+ /** @see [[internal.freeTypes]] */
+ def freeTypes: List[FreeTypeSymbol] = internal.freeTypes(tree)
+
+ /** @see [[internal.substituteSymbols]] */
+ def substituteSymbols(from: List[Symbol], to: List[Symbol]): Tree = internal.substituteSymbols(tree, from, to)
+
+ /** @see [[internal.substituteTypes]] */
+ def substituteTypes(from: List[Symbol], to: List[Type]): Tree = internal.substituteTypes(tree, from, to)
+
+ /** @see [[internal.substituteThis]] */
+ def substituteThis(clazz: Symbol, to: Tree): Tree = internal.substituteThis(tree, clazz, to)
+ }
+
+ /** Extension methods for symbols */
+ type SymbolDecorator[T <: Symbol] <: SymbolDecoratorApi[T]
+
+ /** @see [[SymbolDecorator]] */
+ implicit def symbolDecorator[T <: Symbol](symbol: T): SymbolDecorator[T]
+
+ /** @see [[SymbolDecorator]] */
+ class SymbolDecoratorApi[T <: Symbol](val symbol: T) {
+ /** @see [[internal.isFreeTerm]] */
+ def isFreeTerm: Boolean = internal.isFreeTerm(symbol)
+
+ /** @see [[internal.asFreeTerm]] */
+ def asFreeTerm: FreeTermSymbol = internal.asFreeTerm(symbol)
+
+ /** @see [[internal.isFreeType]] */
+ def isFreeType: Boolean = internal.isFreeType(symbol)
+
+ /** @see [[internal.asFreeType]] */
+ def asFreeType: FreeTypeSymbol = internal.asFreeType(symbol)
+
+ /** @see [[internal.newTermSymbol]] */
+ def newTermSymbol(name: TermName, pos: Position = NoPosition, flags: FlagSet = NoFlags): TermSymbol = internal.newTermSymbol(symbol, name, pos, flags)
+
+ /** @see [[internal.newModuleAndClassSymbol]] */
+ def newModuleAndClassSymbol(name: Name, pos: Position = NoPosition, flags: FlagSet = NoFlags): (ModuleSymbol, ClassSymbol) = internal.newModuleAndClassSymbol(symbol, name, pos, flags)
+
+ /** @see [[internal.newMethodSymbol]] */
+ def newMethodSymbol(name: TermName, pos: Position = NoPosition, flags: FlagSet = NoFlags): MethodSymbol = internal.newMethodSymbol(symbol, name, pos, flags)
+
+ /** @see [[internal.newTypeSymbol]] */
+ def newTypeSymbol(name: TypeName, pos: Position = NoPosition, flags: FlagSet = NoFlags): TypeSymbol = internal.newTypeSymbol(symbol, name, pos, flags)
+
+ /** @see [[internal.newClassSymbol]] */
+ def newClassSymbol(name: TypeName, pos: Position = NoPosition, flags: FlagSet = NoFlags): ClassSymbol = internal.newClassSymbol(symbol, name, pos, flags)
+
+ /** @see [[internal.isErroneous]] */
+ def isErroneous: Boolean = internal.isErroneous(symbol)
+
+ /** @see [[internal.isSkolem]] */
+ def isSkolem: Boolean = internal.isSkolem(symbol)
+
+ /** @see [[internal.deSkolemize]] */
+ def deSkolemize: Symbol = internal.deSkolemize(symbol)
+
+ /** @see [[internal.initialize]] */
+ def initialize: T = internal.initialize(symbol)
+
+ /** @see [[internal.fullyInitialize]] */
+ def fullyInitialize: T = internal.fullyInitialize(symbol)
+
+ /** @see [[internal.flags]] */
+ def flags: FlagSet = internal.flags(symbol)
+ }
+
+ /** Extension methods for types */
+ type TypeDecorator[T <: Type] <: TypeDecoratorApi[T]
+
+ /** @see [[TypeDecorator]] */
+ implicit def typeDecorator[T <: Type](tp: T): TypeDecorator[T]
+
+ /** @see [[TypeDecorator]] */
+ implicit class TypeDecoratorApi[T <: Type](val tp: T) {
+ /** @see [[internal.fullyInitialize]] */
+ def fullyInitialize: T = internal.fullyInitialize(tp)
+ }
+ }
+ }
+
+ /** This is an internal implementation class.
+ * @group Internal
+ */
+ // this API abstracts away the functionality necessary for reification and quasiquotes
+ // it's too gimmicky and unstructured to be exposed directly in the universe
+ // but we need it in a publicly available place for reification to work
+ trait ReificationSupportApi {
+ /** Selects type symbol with given simple name `name` from the defined members of `owner`.
+ */
+ def selectType(owner: Symbol, name: String): TypeSymbol
+
+ /** Selects term symbol with given name and type from the defined members of prefix type
+ */
+ def selectTerm(owner: Symbol, name: String): TermSymbol
+
+ /** Selects overloaded method symbol with given name and index
+ */
+ def selectOverloadedMethod(owner: Symbol, name: String, index: Int): MethodSymbol
+
+ /** A fresh symbol with given name `name`, position `pos` and flags `flags` that has
+ * the current symbol as its owner.
+ */
+ def newNestedSymbol(owner: Symbol, name: Name, pos: Position, flags: FlagSet, isClass: Boolean): Symbol
+
+ def newScopeWith(elems: Symbol*): Scope
+
+ /** Create a fresh free term symbol.
+ * @param name the name of the free variable
+ * @param value the value of the free variable at runtime
+ * @param flags (optional) flags of the free variable
+ * @param origin debug information that tells where this symbol comes from
+ */
+ def newFreeTerm(name: String, value: => Any, flags: FlagSet = NoFlags, origin: String = null): FreeTermSymbol
+
+ /** Create a fresh free type symbol.
+ * @param name the name of the free variable
+ * @param flags (optional) flags of the free variable
+ * @param origin debug information that tells where this symbol comes from
+ */
+ def newFreeType(name: String, flags: FlagSet = NoFlags, origin: String = null): FreeTypeSymbol
+
+ /** Set symbol's type signature to given type.
+ * @return the symbol itself
+ */
+ def setInfo[S <: Symbol](sym: S, tpe: Type): S
+
+ /** Set symbol's annotations to given annotations `annots`.
+ */
+ def setAnnotations[S <: Symbol](sym: S, annots: List[Annotation]): S
+
+ def mkThis(sym: Symbol): Tree
+
+ def mkSelect(qualifier: Tree, sym: Symbol): Select
+
+ def mkIdent(sym: Symbol): Ident
+
+ def mkTypeTree(tp: Type): TypeTree
+
+ def ThisType(sym: Symbol): Type
+
+ def SingleType(pre: Type, sym: Symbol): Type
+
+ def SuperType(thistpe: Type, supertpe: Type): Type
+
+ def ConstantType(value: Constant): ConstantType
+
+ def TypeRef(pre: Type, sym: Symbol, args: List[Type]): Type
+
+ def RefinedType(parents: List[Type], decls: Scope, typeSymbol: Symbol): RefinedType
+
+ def ClassInfoType(parents: List[Type], decls: Scope, typeSymbol: Symbol): ClassInfoType
+
+ def MethodType(params: List[Symbol], resultType: Type): MethodType
+
+ def NullaryMethodType(resultType: Type): NullaryMethodType
+
+ def PolyType(typeParams: List[Symbol], resultType: Type): PolyType
+
+ def ExistentialType(quantified: List[Symbol], underlying: Type): ExistentialType
+
+ def AnnotatedType(annotations: List[Annotation], underlying: Type): AnnotatedType
+
+ def TypeBounds(lo: Type, hi: Type): TypeBounds
+
+ def BoundedWildcardType(bounds: TypeBounds): BoundedWildcardType
+
+ def thisPrefix(sym: Symbol): Type
+
+ def setType[T <: Tree](tree: T, tpe: Type): T
+
+ def setSymbol[T <: Tree](tree: T, sym: Symbol): T
+
+ def toStats(tree: Tree): List[Tree]
+
+ def mkAnnotation(tree: Tree): Tree
+
+ def mkAnnotation(trees: List[Tree]): List[Tree]
+
+ def mkRefineStat(stat: Tree): Tree
+
+ def mkRefineStat(stats: List[Tree]): List[Tree]
+
+ def mkPackageStat(stat: Tree): Tree
+
+ def mkPackageStat(stats: List[Tree]): List[Tree]
+
+ def mkEarlyDef(defn: Tree): Tree
+
+ def mkEarlyDef(defns: List[Tree]): List[Tree]
+
+ def mkRefTree(qual: Tree, sym: Symbol): Tree
+
+ def freshTermName(prefix: String): TermName
+
+ def freshTypeName(prefix: String): TypeName
+
+ val ImplicitParams: ImplicitParamsExtractor
+
+ trait ImplicitParamsExtractor {
+ def apply(paramss: List[List[Tree]], implparams: List[Tree]): List[List[Tree]]
+ def unapply(vparamss: List[List[ValDef]]): Some[(List[List[ValDef]], List[ValDef])]
+ }
+
+ val ScalaDot: ScalaDotExtractor
+
+ trait ScalaDotExtractor {
+ def apply(name: Name): Tree
+ def unapply(tree: Tree): Option[Name]
+ }
+
+ val FlagsRepr: FlagsReprExtractor
+
+ trait FlagsReprExtractor {
+ def apply(value: Long): FlagSet
+ def unapply(flags: Long): Some[Long]
+ }
+
+ val SyntacticTypeApplied: SyntacticTypeAppliedExtractor
+ val SyntacticAppliedType: SyntacticTypeAppliedExtractor
+
+ trait SyntacticTypeAppliedExtractor {
+ def apply(tree: Tree, targs: List[Tree]): Tree
+ def unapply(tree: Tree): Option[(Tree, List[Tree])]
+ }
+
+ val SyntacticApplied: SyntacticAppliedExtractor
+
+ trait SyntacticAppliedExtractor {
+ def apply(tree: Tree, argss: List[List[Tree]]): Tree
+ def unapply(tree: Tree): Some[(Tree, List[List[Tree]])]
+ }
+
+ val SyntacticClassDef: SyntacticClassDefExtractor
+
+ trait SyntacticClassDefExtractor {
+ def apply(mods: Modifiers, name: TypeName, tparams: List[Tree],
+ constrMods: Modifiers, vparamss: List[List[Tree]],
+ earlyDefs: List[Tree], parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef
+ def unapply(tree: Tree): Option[(Modifiers, TypeName, List[TypeDef], Modifiers, List[List[ValDef]],
+ List[Tree], List[Tree], ValDef, List[Tree])]
+ }
+
+ val SyntacticTraitDef: SyntacticTraitDefExtractor
+
+ trait SyntacticTraitDefExtractor {
+ def apply(mods: Modifiers, name: TypeName, tparams: List[Tree],
+ earlyDefs: List[Tree], parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef
+ def unapply(tree: Tree): Option[(Modifiers, TypeName, List[TypeDef],
+ List[Tree], List[Tree], ValDef, List[Tree])]
+ }
+
+ val SyntacticObjectDef: SyntacticObjectDefExtractor
+
+ trait SyntacticObjectDefExtractor {
+ def apply(mods: Modifiers, name: TermName, earlyDefs: List[Tree],
+ parents: List[Tree], selfType: Tree, body: List[Tree]): ModuleDef
+ def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[Tree], ValDef, List[Tree])]
+ }
+
+ val SyntacticPackageObjectDef: SyntacticPackageObjectDefExtractor
+
+ trait SyntacticPackageObjectDefExtractor {
+ def apply(name: TermName, earlyDefs: List[Tree],
+ parents: List[Tree], selfType: Tree, body: List[Tree]): PackageDef
+ def unapply(tree: Tree): Option[(TermName, List[Tree], List[Tree], ValDef, List[Tree])]
+ }
+
+ val SyntacticTuple: SyntacticTupleExtractor
+ val SyntacticTupleType: SyntacticTupleExtractor
+
+ trait SyntacticTupleExtractor {
+ def apply(args: List[Tree]): Tree
+ def unapply(tree: Tree): Option[List[Tree]]
+ }
+
+ val SyntacticBlock: SyntacticBlockExtractor
+
+ trait SyntacticBlockExtractor {
+ def apply(stats: List[Tree]): Tree
+ def unapply(tree: Tree): Option[List[Tree]]
+ }
+
+ val SyntacticNew: SyntacticNewExtractor
+
+ trait SyntacticNewExtractor {
+ def apply(earlyDefs: List[Tree], parents: List[Tree], selfType: Tree, body: List[Tree]): Tree
+ def unapply(tree: Tree): Option[(List[Tree], List[Tree], ValDef, List[Tree])]
+ }
+
+ val SyntacticFunctionType: SyntacticFunctionTypeExtractor
+
+ trait SyntacticFunctionTypeExtractor {
+ def apply(argtpes: List[Tree], restpe: Tree): Tree
+ def unapply(tree: Tree): Option[(List[Tree], Tree)]
+ }
+
+ val SyntacticFunction: SyntacticFunctionExtractor
+
+ trait SyntacticFunctionExtractor {
+ def apply(params: List[Tree], body: Tree): Function
+
+ def unapply(tree: Function): Option[(List[ValDef], Tree)]
+ }
+
+ val SyntacticDefDef: SyntacticDefDefExtractor
+
+ trait SyntacticDefDefExtractor {
+ def apply(mods: Modifiers, name: TermName, tparams: List[Tree],
+ vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef
+
+ def unapply(tree: Tree): Option[(Modifiers, TermName, List[TypeDef], List[List[ValDef]], Tree, Tree)]
+ }
+
+ val SyntacticValDef: SyntacticValDefExtractor
+ val SyntacticVarDef: SyntacticValDefExtractor
+
+ trait SyntacticValDefExtractor {
+ def apply(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree): ValDef
+ def unapply(tree: Tree): Option[(Modifiers, TermName, Tree, Tree)]
+ }
+
+ val SyntacticPatDef: SyntacticPatDefExtractor
+
+ trait SyntacticPatDefExtractor {
+ def apply(mods: Modifiers, pat: Tree, tpt: Tree, rhs: Tree): List[ValDef]
+ }
+
+ val SyntacticAssign: SyntacticAssignExtractor
+
+ trait SyntacticAssignExtractor {
+ def apply(lhs: Tree, rhs: Tree): Tree
+ def unapply(tree: Tree): Option[(Tree, Tree)]
+ }
+
+ val SyntacticValFrom: SyntacticValFromExtractor
+
+ trait SyntacticValFromExtractor {
+ def apply(pat: Tree, rhs: Tree): Tree
+ def unapply(tree: Tree): Option[(Tree, Tree)]
+ }
+
+ val SyntacticValEq: SyntacticValEqExtractor
+
+ trait SyntacticValEqExtractor {
+ def apply(pat: Tree, rhs: Tree): Tree
+ def unapply(tree: Tree): Option[(Tree, Tree)]
+ }
+
+ val SyntacticFilter: SyntacticFilterExtractor
+
+ trait SyntacticFilterExtractor {
+ def apply(test: Tree): Tree
+ def unapply(tree: Tree): Option[(Tree)]
+ }
+
+ val SyntacticEmptyTypeTree: SyntacticEmptyTypeTreeExtractor
+
+ trait SyntacticEmptyTypeTreeExtractor {
+ def apply(): TypeTree
+ def unapply(tt: TypeTree): Boolean
+ }
+
+ val SyntacticFor: SyntacticForExtractor
+ val SyntacticForYield: SyntacticForExtractor
+
+ trait SyntacticForExtractor {
+ def apply(enums: List[Tree], body: Tree): Tree
+ def unapply(tree: Tree): Option[(List[Tree], Tree)]
+ }
+
+ def UnliftListElementwise[T](unliftable: Unliftable[T]): UnliftListElementwise[T]
+ trait UnliftListElementwise[T] {
+ def unapply(lst: List[Tree]): Option[List[T]]
+ }
+
+ def UnliftListOfListsElementwise[T](unliftable: Unliftable[T]): UnliftListOfListsElementwise[T]
+ trait UnliftListOfListsElementwise[T] {
+ def unapply(lst: List[List[Tree]]): Option[List[List[T]]]
+ }
+
+ val SyntacticPartialFunction: SyntacticPartialFunctionExtractor
+ trait SyntacticPartialFunctionExtractor {
+ def apply(cases: List[Tree]): Match
+ def unapply(tree: Tree): Option[List[CaseDef]]
+ }
+
+ val SyntacticMatch: SyntacticMatchExtractor
+ trait SyntacticMatchExtractor {
+ def apply(scrutinee: Tree, cases: List[Tree]): Match
+ def unapply(tree: Match): Option[(Tree, List[CaseDef])]
+ }
+
+ val SyntacticTry: SyntacticTryExtractor
+ trait SyntacticTryExtractor {
+ def apply(block: Tree, catches: List[Tree], finalizer: Tree): Try
+ def unapply(tree: Try): Option[(Tree, List[CaseDef], Tree)]
+ }
+
+ val SyntacticTermIdent: SyntacticTermIdentExtractor
+ trait SyntacticTermIdentExtractor {
+ def apply(name: TermName, isBackquoted: Boolean = false): Ident
+ def unapply(id: Ident): Option[(TermName, Boolean)]
+ }
+
+ val SyntacticTypeIdent: SyntacticTypeIdentExtractor
+ trait SyntacticTypeIdentExtractor {
+ def apply(name: TypeName): Ident
+ def unapply(tree: Tree): Option[TypeName]
+ }
+
+ val SyntacticImport: SyntacticImportExtractor
+ trait SyntacticImportExtractor {
+ def apply(expr: Tree, selectors: List[Tree]): Import
+ def unapply(imp: Import): Some[(Tree, List[Tree])]
+ }
+
+ val SyntacticSelectType: SyntacticSelectTypeExtractor
+ trait SyntacticSelectTypeExtractor {
+ def apply(qual: Tree, name: TypeName): Select
+ def unapply(tree: Tree): Option[(Tree, TypeName)]
+ }
+
+ val SyntacticSelectTerm: SyntacticSelectTermExtractor
+ trait SyntacticSelectTermExtractor {
+ def apply(qual: Tree, name: TermName): Select
+ def unapply(tree: Tree): Option[(Tree, TermName)]
+ }
+
+ val SyntacticCompoundType: SyntacticCompoundTypeExtractor
+ trait SyntacticCompoundTypeExtractor {
+ def apply(parents: List[Tree], defns: List[Tree]): CompoundTypeTree
+ def unapply(tree: Tree): Option[(List[Tree], List[Tree])]
+ }
+
+ val SyntacticSingletonType: SyntacitcSingletonTypeExtractor
+ trait SyntacitcSingletonTypeExtractor {
+ def apply(tree: Tree): SingletonTypeTree
+ def unapply(tree: Tree): Option[Tree]
+ }
+
+ val SyntacticTypeProjection: SyntacticTypeProjectionExtractor
+ trait SyntacticTypeProjectionExtractor {
+ def apply(qual: Tree, name: TypeName): SelectFromTypeTree
+ def unapply(tree: Tree): Option[(Tree, TypeName)]
+ }
+
+ val SyntacticAnnotatedType: SyntacticAnnotatedTypeExtractor
+ trait SyntacticAnnotatedTypeExtractor {
+ def apply(tpt: Tree, annot: Tree): Annotated
+ def unapply(tree: Tree): Option[(Tree, Tree)]
+ }
+
+ val SyntacticExistentialType: SyntacticExistentialTypeExtractor
+ trait SyntacticExistentialTypeExtractor {
+ def apply(tpt: Tree, where: List[Tree]): ExistentialTypeTree
+ def unapply(tree: Tree): Option[(Tree, List[MemberDef])]
+ }
+ }
+
+ @deprecated("Use `internal.reificationSupport` instead", "2.11.0")
+ val build: ReificationSupportApi
+
+ @deprecated("Use `internal.ReificationSupportApi` instead", "2.11.0")
+ type BuildApi = ReificationSupportApi
+
+ /** This trait provides support for importers, a facility to migrate reflection artifacts between universes.
+ * ''Note: this trait should typically be used only rarely.''
+ *
+ * Reflection artifacts, such as [[scala.reflect.api.Symbols Symbols]] and [[scala.reflect.api.Types Types]],
+ * are contained in [[scala.reflect.api.Universe Universe]]s. Typically all processing happens
+ * within a single `Universe` (e.g. a compile-time macro `Universe` or a runtime reflection `Universe`), but sometimes
+ * there is a need to migrate artifacts from one `Universe` to another. For example, runtime compilation works by
+ * importing runtime reflection trees into a runtime compiler universe, compiling the importees and exporting the
+ * result back.
+ *
+ * Reflection artifacts are firmly grounded in their `Universe`s, which is reflected by the fact that types of artifacts
+ * from different universes are not compatible. By using `Importer`s, however, they be imported from one universe
+ * into another. For example, to import `foo.bar.Baz` from the source `Universe` to the target `Universe`,
+ * an importer will first check whether the entire owner chain exists in the target `Universe`.
+ * If it does, then nothing else will be done. Otherwise, the importer will recreate the entire owner chain
+ * and will import the corresponding type signatures into the target `Universe`.
+ *
+ * Since importers match `Symbol` tables of the source and the target `Universe`s using plain string names,
+ * it is programmer's responsibility to make sure that imports don't distort semantics, e.g., that
+ * `foo.bar.Baz` in the source `Universe` means the same that `foo.bar.Baz` does in the target `Universe`.
+ *
+ * === Example ===
+ *
+ * Here's how one might implement a macro that performs compile-time evaluation of its argument
+ * by using a runtime compiler to compile and evaluate a tree that belongs to a compile-time compiler:
+ *
+ * {{{
+ * def staticEval[T](x: T) = macro staticEval[T]
+ *
+ * def staticEval[T](c: scala.reflect.macros.blackbox.Context)(x: c.Expr[T]) = {
+ * // creates a runtime reflection universe to host runtime compilation
+ * import scala.reflect.runtime.{universe => ru}
+ * val mirror = ru.runtimeMirror(c.libraryClassLoader)
+ * import scala.tools.reflect.ToolBox
+ * val toolBox = mirror.mkToolBox()
+ *
+ * // runtime reflection universe and compile-time macro universe are different
+ * // therefore an importer is needed to bridge them
+ * // currently mkImporter requires a cast to correctly assign the path-dependent types
+ * val importer0 = ru.internal.mkImporter(c.universe)
+ * val importer = importer0.asInstanceOf[ru.internal.Importer { val from: c.universe.type }]
+ *
+ * // the created importer is used to turn a compiler tree into a runtime compiler tree
+ * // both compilers use the same classpath, so semantics remains intact
+ * val imported = importer.importTree(tree)
+ *
+ * // after the tree is imported, it can be evaluated as usual
+ * val tree = toolBox.untypecheck(imported.duplicate)
+ * val valueOfX = toolBox.eval(imported).asInstanceOf[T]
+ * ...
+ * }
+ * }}}
+ *
+ * @group Internal
+ */
+ // SI-6241: move importers to a mirror
+ trait Importer {
+ /** The source universe of reflection artifacts that will be processed.
+ * The target universe is universe that created this importer with `mkImporter`.
+ */
+ val from: Universe
+
+ /** An importer that works in reverse direction, namely:
+ * imports reflection artifacts from the current universe to the universe specified in `from`.
+ */
+ val reverse: from.Importer { val from: self.type }
+
+ /** In the current universe, locates or creates a symbol that corresponds to the provided symbol in the source universe.
+ * If necessary imports the owner chain, companions, type signature, annotations and attachments.
+ */
+ def importSymbol(sym: from.Symbol): Symbol
+
+ /** In the current universe, locates or creates a type that corresponds to the provided type in the source universe.
+ * If necessary imports the underlying symbols, annotations, scopes and trees.
+ */
+ def importType(tpe: from.Type): Type
+
+ /** In the current universe, creates a tree that corresponds to the provided tree in the source universe.
+ * If necessary imports the underlying symbols, types and attachments.
+ */
+ def importTree(tree: from.Tree): Tree
+
+ /** In the current universe, creates a position that corresponds to the provided position in the source universe.
+ */
+ def importPosition(pos: from.Position): Position
+ }
+
+ @deprecated("Use `internal.createImporter` instead", "2.11.0")
+ def mkImporter(from0: Universe): Importer { val from: from0.type } = internal.createImporter(from0)
+
+ /** Marks underlying reference to id as boxed.
+ *
+ * <b>Precondition:<\b> id must refer to a captured variable
+ * A reference such marked will refer to the boxed entity, no dereferencing
+ * with `.elem` is done on it.
+ * This tree node can be emitted by macros such as reify that call referenceCapturedVariable.
+ * It is eliminated in LambdaLift, where the boxing conversion takes place.
+ * @group Internal
+ * @template
+ */
+ type ReferenceToBoxed >: Null <: ReferenceToBoxedApi with TermTree
+
+ /** The constructor/extractor for `ReferenceToBoxed` instances.
+ * @group Internal
+ */
+ val ReferenceToBoxed: ReferenceToBoxedExtractor
+
+ /** An extractor class to create and pattern match with syntax `ReferenceToBoxed(ident)`.
+ * This AST node does not have direct correspondence to Scala code,
+ * and is emitted by macros to reference capture vars directly without going through `elem`.
+ *
+ * For example:
+ *
+ * var x = ...
+ * fun { x }
+ *
+ * Will emit:
+ *
+ * Ident(x)
+ *
+ * Which gets transformed to:
+ *
+ * Select(Ident(x), "elem")
+ *
+ * If `ReferenceToBoxed` were used instead of Ident, no transformation would be performed.
+ * @group Internal
+ */
+ abstract class ReferenceToBoxedExtractor {
+ def apply(ident: Ident): ReferenceToBoxed
+ def unapply(referenceToBoxed: ReferenceToBoxed): Option[Ident]
+ }
+
+ /** The API that all references support
+ * @group Internal
+ */
+ trait ReferenceToBoxedApi extends TermTreeApi { this: ReferenceToBoxed =>
+ /** The underlying reference. */
+ def ident: Tree
+ }
+
+ /** Tag that preserves the identity of `ReferenceToBoxed` in the face of erasure.
+ * Can be used for pattern matching, instance tests, serialization and the like.
+ * @group Internal
+ */
+ implicit val ReferenceToBoxedTag: ClassTag[ReferenceToBoxed]
+
+ /** The type of free terms introduced by reification.
+ * @group Internal
+ * @template
+ */
+ type FreeTermSymbol >: Null <: FreeTermSymbolApi with TermSymbol
+
+ /** The API of free term symbols.
+ * The main source of information about symbols is the [[Symbols]] page.
+ *
+ * $SYMACCESSORS
+ * @group Internal
+ */
+ trait FreeTermSymbolApi extends TermSymbolApi { this: FreeTermSymbol =>
+ /** The place where this symbol has been spawned
+ *
+ * @group FreeTerm
+ */
+ def origin: String
+
+ /** The valus this symbol refers to
+ *
+ * @group FreeTerm
+ */
+ def value: Any
+ }
+
+ /** Tag that preserves the identity of `FreeTermSymbol` in the face of erasure.
+ * Can be used for pattern matching, instance tests, serialization and the like.
+ * @group Internal
+ */
+ implicit val FreeTermSymbolTag: ClassTag[FreeTermSymbol]
+
+ /** The type of free types introduced by reification.
+ * @group Internal
+ * @template
+ */
+ type FreeTypeSymbol >: Null <: FreeTypeSymbolApi with TypeSymbol
+
+ /** The API of free type symbols.
+ * The main source of information about symbols is the [[Symbols]] page.
+ *
+ * $SYMACCESSORS
+ * @group Internal
+ */
+ trait FreeTypeSymbolApi extends TypeSymbolApi { this: FreeTypeSymbol =>
+ /** The place where this symbol has been spawned
+ *
+ * @group FreeType
+ */
+ def origin: String
+ }
+
+ /** Tag that preserves the identity of `FreeTermSymbol` in the face of erasure.
+ * Can be used for pattern matching, instance tests, serialization and the like.
+ * @group Internal
+ */
+ implicit val FreeTypeSymbolTag: ClassTag[FreeTypeSymbol]
+
+ /** Provides enrichments to ensure source compatibility between Scala 2.10 and Scala 2.11.
+ * If in your reflective program for Scala 2.10 you've used something that's now become an internal API,
+ * a single `compat._` import will fix things for you.
+ * @group Internal
+ */
+ val compat: Compat
+
+ /** @see [[compat]]
+ * @group Internal
+ */
+ type Compat <: CompatApi
+
+ /** Presence of an implicit value of this type in scope
+ * indicates that source compatibility with Scala 2.10 has been enabled.
+ * @group Internal
+ */
+ @scala.annotation.implicitNotFound("This method has been removed from the public API. Import compat._ or migrate away.")
+ class CompatToken
+
+ /** @see [[compat]]
+ * @group Internal
+ */
+ trait CompatApi {
+ /** @see [[CompatToken]] */
+ implicit val token = new CompatToken
+
+ /** @see [[InternalApi.typeTagToManifest]] */
+ @deprecated("Use `internal.typeTagToManifest` instead", "2.11.0")
+ def typeTagToManifest[T: ClassTag](mirror: Any, tag: Universe#TypeTag[T]): Manifest[T] =
+ internal.typeTagToManifest(mirror, tag)
+
+ /** @see [[InternalApi.manifestToTypeTag]] */
+ @deprecated("Use `internal.manifestToTypeTag` instead", "2.11.0")
+ def manifestToTypeTag[T](mirror: Any, manifest: Manifest[T]): Universe#TypeTag[T] =
+ internal.manifestToTypeTag(mirror, manifest)
+
+ /** @see [[InternalApi.newScopeWith]] */
+ @deprecated("Use `internal.newScopeWith` instead", "2.11.0")
+ def newScopeWith(elems: Symbol*): Scope =
+ internal.newScopeWith(elems: _*)
+
+ /** Scala 2.10 compatibility enrichments for BuildApi. */
+ implicit class CompatibleBuildApi(api: BuildApi) {
+ /** @see [[BuildApi.setInfo]] */
+ @deprecated("Use `internal.reificationSupport.setInfo` instead", "2.11.0")
+ def setTypeSignature[S <: Symbol](sym: S, tpe: Type): S = internal.reificationSupport.setInfo(sym, tpe)
+
+ /** @see [[BuildApi.FlagsRepr]] */
+ @deprecated("Use `internal.reificationSupport.FlagsRepr` instead", "2.11.0")
+ def flagsFromBits(bits: Long): FlagSet = internal.reificationSupport.FlagsRepr(bits)
+
+ /** @see [[BuildApi.noSelfType]] */
+ @deprecated("Use `noSelfType` instead", "2.11.0")
+ def emptyValDef: ValDef = noSelfType
+
+ /** @see [[BuildApi.mkThis]] */
+ @deprecated("Use `internal.reificationSupport.mkThis` instead", "2.11.0")
+ def This(sym: Symbol): Tree = internal.reificationSupport.mkThis(sym)
+
+ /** @see [[BuildApi.mkSelect]] */
+ @deprecated("Use `internal.reificationSupport.mkSelect` instead", "2.11.0")
+ def Select(qualifier: Tree, sym: Symbol): Select = internal.reificationSupport.mkSelect(qualifier, sym)
+
+ /** @see [[BuildApi.mkIdent]] */
+ @deprecated("Use `internal.reificationSupport.mkIdent` instead", "2.11.0")
+ def Ident(sym: Symbol): Ident = internal.reificationSupport.mkIdent(sym)
+
+ /** @see [[BuildApi.mkTypeTree]] */
+ @deprecated("Use `internal.reificationSupport.mkTypeTree` instead", "2.11.0")
+ def TypeTree(tp: Type): TypeTree = internal.reificationSupport.mkTypeTree(tp)
+ }
+
+ /** Scala 2.10 compatibility enrichments for Tree. */
+ implicit class CompatibleTree(tree: Tree) {
+ /** @see [[InternalApi.freeTerms]] */
+ @deprecated("Use `internal.freeTerms` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def freeTerms: List[FreeTermSymbol] = internal.freeTerms(tree)
+
+ /** @see [[InternalApi.freeTypes]] */
+ @deprecated("Use `internal.freeTerms` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def freeTypes: List[FreeTypeSymbol] = internal.freeTypes(tree)
+
+ /** @see [[InternalApi.substituteSymbols]] */
+ @deprecated("Use `internal.substituteSymbols` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def substituteSymbols(from: List[Symbol], to: List[Symbol]): Tree = internal.substituteSymbols(tree, from, to)
+
+ /** @see [[InternalApi.substituteTypes]] */
+ @deprecated("Use `internal.substituteTypes` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def substituteTypes(from: List[Symbol], to: List[Type]): Tree = internal.substituteTypes(tree, from, to)
+
+ /** @see [[InternalApi.substituteThis]] */
+ @deprecated("Use `internal.substituteThis` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def substituteThis(clazz: Symbol, to: Tree): Tree = internal.substituteThis(tree, clazz, to)
+ }
+
+ /** Scala 2.10 compatibility enrichments for Tree. */
+ implicit class CompatibleSymbol(symbol: Symbol) {
+ @deprecated("This API is unreliable. Use `isPrivateThis` or `isProtectedThis` instead", "2.11.0")
+ def isLocal: Boolean = symbol.asInstanceOf[scala.reflect.internal.Symbols#Symbol].isLocal
+
+ @deprecated("This API is unreliable. Use `overrides.nonEmpty` instead", "2.11.0")
+ def isOverride: Boolean = symbol.asInstanceOf[scala.reflect.internal.Symbols#Symbol].isOverride
+
+ /** @see [[InternalApi.isFreeTerm]] */
+ @deprecated("Use `internal.isFreeTerm` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def isFreeTerm: Boolean = internal.isFreeTerm(symbol)
+
+ /** @see [[InternalApi.asFreeTerm]] */
+ @deprecated("Use `internal.asFreeTerm` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def asFreeTerm: FreeTermSymbol = internal.asFreeTerm(symbol)
+
+ /** @see [[InternalApi.isFreeType]] */
+ @deprecated("Use `internal.isFreeType` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def isFreeType: Boolean = internal.isFreeType(symbol)
+
+ /** @see [[InternalApi.asFreeType]] */
+ @deprecated("Use `internal.asFreeType` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def asFreeType: FreeTypeSymbol = internal.asFreeType(symbol)
+
+ /** @see [[InternalApi.asFreeType]] */
+ @deprecated("Use `internal.newTermSymbol` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def newTermSymbol(name: TermName, pos: Position = NoPosition, flags: FlagSet = NoFlags): TermSymbol = internal.newTermSymbol(symbol, name, pos, flags)
+
+ /** @see [[InternalApi.asFreeType]] */
+ @deprecated("Use `internal.newModuleAndClassSymbol` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def newModuleAndClassSymbol(name: Name, pos: Position = NoPosition, flags: FlagSet = NoFlags): (ModuleSymbol, ClassSymbol) = internal.newModuleAndClassSymbol(symbol, name, pos, flags)
+
+ /** @see [[InternalApi.asFreeType]] */
+ @deprecated("Use `internal.newMethodSymbol` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def newMethodSymbol(name: TermName, pos: Position = NoPosition, flags: FlagSet = NoFlags): MethodSymbol = internal.newMethodSymbol(symbol, name, pos, flags)
+
+ /** @see [[InternalApi.asFreeType]] */
+ @deprecated("Use `internal.newTypeSymbol` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def newTypeSymbol(name: TypeName, pos: Position = NoPosition, flags: FlagSet = NoFlags): TypeSymbol = internal.newTypeSymbol(symbol, name, pos, flags)
+
+ /** @see [[InternalApi.asFreeType]] */
+ @deprecated("Use `internal.newClassSymbol` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def newClassSymbol(name: TypeName, pos: Position = NoPosition, flags: FlagSet = NoFlags): ClassSymbol = internal.newClassSymbol(symbol, name, pos, flags)
+
+ /** @see [[InternalApi.asFreeType]] */
+ @deprecated("Use `internal.isErroneous` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def isErroneous: Boolean = internal.isErroneous(symbol)
+
+ /** @see [[InternalApi.asFreeType]] */
+ @deprecated("Use `internal.isSkolem` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def isSkolem: Boolean = internal.isSkolem(symbol)
+
+ /** @see [[InternalApi.asFreeType]] */
+ @deprecated("Use `internal.deSkolemize` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def deSkolemize: Symbol = internal.deSkolemize(symbol)
+ }
+
+ /** @see [[InternalApi.singleType]] */
+ @deprecated("Use `internal.singleType` instead", "2.11.0")
+ def singleType(pre: Type, sym: Symbol): Type = internal.singleType(pre, sym)
+
+ /** @see [[InternalApi.refinedType]] */
+ @deprecated("Use `internal.refinedType` instead", "2.11.0")
+ def refinedType(parents: List[Type], owner: Symbol, decls: Scope, pos: Position): Type = internal.refinedType(parents, owner, decls, pos)
+
+ /** @see [[InternalApi.refinedType]] */
+ @deprecated("Use `internal.refinedType` instead", "2.11.0")
+ def refinedType(parents: List[Type], owner: Symbol): Type = internal.refinedType(parents, owner)
+
+ /** @see [[InternalApi.typeRef]] */
+ @deprecated("Use `internal.typeRef` instead", "2.11.0")
+ def typeRef(pre: Type, sym: Symbol, args: List[Type]): Type = internal.typeRef(pre, sym, args)
+
+ /** @see [[InternalApi.intersectionType]] */
+ @deprecated("Use `internal.intersectionType` instead", "2.11.0")
+ def intersectionType(tps: List[Type]): Type = internal.intersectionType(tps)
+
+ /** @see [[InternalApi.intersectionType]] */
+ @deprecated("Use `internal.intersectionType` instead", "2.11.0")
+ def intersectionType(tps: List[Type], owner: Symbol): Type = internal.intersectionType(tps, owner)
+
+ /** @see [[InternalApi.polyType]] */
+ @deprecated("Use `internal.polyType` instead", "2.11.0")
+ def polyType(tparams: List[Symbol], tpe: Type): Type = internal.polyType(tparams, tpe)
+
+ /** @see [[InternalApi.existentialAbstraction]] */
+ @deprecated("Use `internal.existentialAbstraction` instead", "2.11.0")
+ def existentialAbstraction(tparams: List[Symbol], tpe0: Type): Type = internal.existentialAbstraction(tparams, tpe0)
+ }
+}
diff --git a/src/reflect/scala/reflect/api/JavaMirrors.scala b/src/reflect/scala/reflect/api/JavaMirrors.scala
deleted file mode 100644
index b678033e1a..0000000000
--- a/src/reflect/scala/reflect/api/JavaMirrors.scala
+++ /dev/null
@@ -1,56 +0,0 @@
-package scala.reflect
-package api
-
-/**
- * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
- *
- * A refinement of [[scala.reflect.api.Mirror]] for runtime reflection using JVM classloaders.
- *
- * This refinement equips mirrors with reflection capabilities for the JVM. `JavaMirror` can
- * convert Scala reflection artifacts (symbols and types) into Java reflection artifacts (classes)
- * and vice versa. It can also perform reflective invocations (getting/setting field values,
- * calling methods, etc).
- *
- * For more information about `Mirrors`s, see [[scala.reflect.api.Mirrors]] or the
- * [[http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html Reflection Guide: Mirrors]]
- *
- * @groupname JavaMirrors Java Mirrors
- * @group ReflectionAPI
- */
-trait JavaMirrors { self: JavaUniverse =>
-
- /** In runtime reflection universes, runtime representation of a class is `java.lang.Class`.
- * @group JavaMirrors
- */
- type RuntimeClass = java.lang.Class[_]
-
- /** In runtime reflection universes, mirrors are `JavaMirrors`.
- * @group JavaMirrors
- */
- override type Mirror >: Null <: JavaMirror
-
- /** A refinement of [[scala.reflect.api.Mirror]] for runtime reflection using JVM classloaders.
- *
- * With this upgrade, mirrors become capable of converting Scala reflection artifacts (symbols and types)
- * into Java reflection artifacts (classes) and vice versa. Consequently, refined mirrors
- * become capable of performing reflective invocations (getting/setting field values, calling methods, etc).
- *
- * For more information about `Mirrors`s, see [[scala.reflect.api.Mirrors]] or the
- * [[http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html Reflection Guide: Mirrors]]
- *
- * @group JavaMirrors
- */
- trait JavaMirror extends scala.reflect.api.Mirror[self.type] with RuntimeMirror {
- val classLoader: ClassLoader
- override def toString = s"JavaMirror with ${runtime.ReflectionUtils.show(classLoader)}"
- }
-
- /** Creates a runtime reflection mirror from a JVM classloader.
- *
- * For more information about `Mirrors`s, see [[scala.reflect.api.Mirrors]] or the
- * [[http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html Reflection Guide: Mirrors]]
- *
- * @group JavaMirrors
- */
- def runtimeMirror(cl: ClassLoader): Mirror
-}
diff --git a/src/reflect/scala/reflect/api/JavaUniverse.scala b/src/reflect/scala/reflect/api/JavaUniverse.scala
index 04d091ee9d..88107ea117 100644
--- a/src/reflect/scala/reflect/api/JavaUniverse.scala
+++ b/src/reflect/scala/reflect/api/JavaUniverse.scala
@@ -1,13 +1,16 @@
-package scala.reflect
+package scala
+package reflect
package api
/**
- * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
+ * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A refinement of [[scala.reflect.api.Universe]] for runtime reflection using JVM classloaders.
+ * A refinement of [[scala.reflect.api.Universe]] for runtime reflection using JVM classloaders.
*
- * The refinement consists of an upgrade to the mirror API, which gets extended from [[scala.reflect.api.Mirror]]
- * to [[scala.reflect.api.JavaMirrors#JavaMirror]].
+ * This refinement equips mirrors with reflection capabilities for the JVM. `JavaMirror` can
+ * convert Scala reflection artifacts (symbols and types) into Java reflection artifacts (classes)
+ * and vice versa. It can also perform reflective invocations (getting/setting field values,
+ * calling methods, etc).
*
* See the [[http://docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]] for details on how to use runtime reflection.
*
@@ -16,31 +19,41 @@ package api
*
* @contentDiagram hideNodes "*Api"
*/
-trait JavaUniverse extends Universe with JavaMirrors { self =>
+trait JavaUniverse extends Universe { self =>
- /* @group JavaUniverse */
- override def typeTagToManifest[T: ClassTag](mirror0: Any, tag: Universe # TypeTag[T]): Manifest[T] = {
- // SI-6239: make this conversion more precise
- val mirror = mirror0.asInstanceOf[Mirror]
- val runtimeClass = mirror.runtimeClass(tag.in(mirror).tpe)
- Manifest.classType(runtimeClass).asInstanceOf[Manifest[T]]
+ /** In runtime reflection universes, runtime representation of a class is `java.lang.Class`.
+ * @group JavaMirrors
+ */
+ type RuntimeClass = java.lang.Class[_]
+ implicit val RuntimeClassTag: ClassTag[RuntimeClass] = ClassTag[RuntimeClass](classOf[RuntimeClass])
+
+ /** In runtime reflection universes, mirrors are `JavaMirrors`.
+ * @group JavaMirrors
+ */
+ override type Mirror >: Null <: JavaMirror
+
+ /** A refinement of [[scala.reflect.api.Mirror]] for runtime reflection using JVM classloaders.
+ *
+ * With this upgrade, mirrors become capable of converting Scala reflection artifacts (symbols and types)
+ * into Java reflection artifacts (classes) and vice versa. Consequently, refined mirrors
+ * become capable of performing reflective invocations (getting/setting field values, calling methods, etc).
+ *
+ * For more information about `Mirrors`s, see [[scala.reflect.api.Mirrors]] or the
+ * [[http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html Reflection Guide: Mirrors]]
+ *
+ * @group JavaMirrors
+ */
+ trait JavaMirror extends scala.reflect.api.Mirror[self.type] with RuntimeMirror {
+ val classLoader: ClassLoader
+ override def toString = s"JavaMirror with ${runtime.ReflectionUtils.show(classLoader)}"
}
- /* @group JavaUniverse */
- override def manifestToTypeTag[T](mirror0: Any, manifest: Manifest[T]): Universe # TypeTag[T] =
- TypeTag(mirror0.asInstanceOf[Mirror], new TypeCreator {
- def apply[U <: Universe with Singleton](mirror: scala.reflect.api.Mirror[U]): U # Type = {
- mirror.universe match {
- case ju: JavaUniverse =>
- val jm = mirror.asInstanceOf[ju.Mirror]
- val sym = jm.classSymbol(manifest.erasure)
- val tpe =
- if (manifest.typeArguments.isEmpty) sym.toType
- else ju.appliedType(sym.toTypeConstructor, manifest.typeArguments map (targ => ju.manifestToTypeTag(jm, targ)) map (_.in(jm).tpe))
- tpe.asInstanceOf[U # Type]
- case u =>
- u.manifestToTypeTag(mirror.asInstanceOf[u.Mirror], manifest).in(mirror).tpe
- }
- }
- })
-}
+ /** Creates a runtime reflection mirror from a JVM classloader.
+ *
+ * For more information about `Mirrors`s, see [[scala.reflect.api.Mirrors]] or the
+ * [[http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html Reflection Guide: Mirrors]]
+ *
+ * @group JavaMirrors
+ */
+ def runtimeMirror(cl: ClassLoader): Mirror
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/api/Liftables.scala b/src/reflect/scala/reflect/api/Liftables.scala
new file mode 100644
index 0000000000..673dbce6f5
--- /dev/null
+++ b/src/reflect/scala/reflect/api/Liftables.scala
@@ -0,0 +1,75 @@
+package scala
+package reflect
+package api
+
+trait Liftables { self: Universe =>
+
+ /** A type class that defines a representation of `T` as a `Tree`.
+ *
+ * @see [[http://docs.scala-lang.org/overviews/quasiquotes/lifting.html]]
+ */
+ trait Liftable[T] {
+ def apply(value: T): Tree
+ }
+
+ /** Companion to `Liftable` type class that contains standard instances
+ * and provides a helper `apply` method to simplify creation of new ones.
+ */
+ object Liftable extends StandardLiftableInstances {
+ /** A helper method that simplifies creation of `Liftable` instances.
+ * Takes a type and a function that maps that type to a tree representation.
+ *
+ * For example to write Liftable for object one might use it like:
+ *
+ * {{{
+ * scala> object O
+ *
+ * scala> val Oref = symbolOf[O.type].asClass.module
+ *
+ * scala> implicit val liftO = Liftable[O.type] { _ => q"$Oref" }
+ *
+ * scala> val lifted = q"$O"
+ * lifted: universe.Tree = O
+ * }}}
+ *
+ * @see [[http://docs.scala-lang.org/overviews/quasiquotes/lifting.html]]
+ */
+ def apply[T](f: T => Tree): Liftable[T] =
+ new Liftable[T] { def apply(value: T): Tree = f(value) }
+ }
+
+ /** A type class that defines a way to extract instance of `T` from a `Tree`.
+ *
+ * @see [[http://docs.scala-lang.org/overviews/quasiquotes/unlifting.html]]
+ */
+ trait Unliftable[T] {
+ def unapply(tree: Tree): Option[T]
+ }
+
+ /** Companion to `Unliftable` type class that contains standard instances
+ * and provides a helper `apply` method to simplify creation of new ones.
+ */
+ object Unliftable extends StandardUnliftableInstances {
+ /** A helper method that simplifies creation of `Unliftable` instances.
+ * Takes a partial function which is defined on correct representations of `T`
+ * and returns corresponing instances.
+ *
+ * For example to extract a reference to an object as object itself:
+ *
+ * {{{
+ * scala> object O
+ *
+ * scala> val Oref = symbolOf[O.type].asClass.module
+ *
+ * scala> implicit val unliftO = Unliftable[O.type] { case t if t.symbol == Oref => O }
+ *
+ * scala> val q"${_: O.type}" = q"$Oref"
+ * }}}
+ *
+ * @see [[http://docs.scala-lang.org/overviews/quasiquotes/unlifting.html]]
+ */
+ def apply[T](pf: PartialFunction[Tree, T]): Unliftable[T] = new Unliftable[T] {
+ def unapply(value: Tree): Option[T] = pf.lift(value)
+ }
+ }
+}
diff --git a/src/reflect/scala/reflect/api/Mirror.scala b/src/reflect/scala/reflect/api/Mirror.scala
index 1223326d7c..318fdb369a 100644
--- a/src/reflect/scala/reflect/api/Mirror.scala
+++ b/src/reflect/scala/reflect/api/Mirror.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package api
/**
@@ -49,16 +50,16 @@ abstract class Mirror[U <: Universe with Singleton] {
* If you need a symbol that corresponds to the type alias itself, load it directly from the package class:
*
* scala> cm.staticClass("scala.List")
- * res0: reflect.runtime.universe.ClassSymbol = class List
+ * res0: scala.reflect.runtime.universe.ClassSymbol = class List
*
* scala> res0.fullName
* res1: String = scala.collection.immutable.List
*
* scala> cm.staticPackage("scala")
- * res2: reflect.runtime.universe.ModuleSymbol = package scala
+ * res2: scala.reflect.runtime.universe.ModuleSymbol = package scala
*
- * scala> res2.moduleClass.typeSignature member newTypeName("List")
- * res3: reflect.runtime.universe.Symbol = type List
+ * scala> res2.moduleClass.info member newTypeName("List")
+ * res3: scala.reflect.runtime.universe.Symbol = type List
*
* scala> res3.fullName
* res4: String = scala.List
@@ -78,11 +79,10 @@ abstract class Mirror[U <: Universe with Singleton] {
* }
*
* staticClass("foo.B") will resolve to the symbol corresponding to the class B declared in the package foo, and
- * staticClass("foo.A") will throw a MissingRequirementException (which is exactly what scalac would do if this
- * fully qualified class name is written inside any package in a Scala program).
+ * staticClass("foo.A") will throw a ScalaReflectionException.
*
* In the example above, to load a symbol that corresponds to the class B declared in the object foo,
- * use staticModule("foo") to load the module symbol and then navigate typeSignature.members of its moduleClass.
+ * use staticModule("foo") to load the module symbol and then navigate info.members of its moduleClass.
* @group Mirror
*/
def staticClass(fullName: String): U#ClassSymbol
@@ -105,11 +105,10 @@ abstract class Mirror[U <: Universe with Singleton] {
* }
*
* staticModule("foo.B") will resolve to the symbol corresponding to the object B declared in the package foo, and
- * staticModule("foo.A") will throw a MissingRequirementException (which is exactly what scalac would do if this
- * fully qualified class name is written inside any package in a Scala program).
+ * staticModule("foo.A") will throw a ScalaReflectionException
*
* In the example above, to load a symbol that corresponds to the object B declared in the object foo,
- * use staticModule("foo") to load the module symbol and then navigate typeSignature.members of its moduleClass.
+ * use staticModule("foo") to load the module symbol and then navigate info.members of its moduleClass.
* @group Mirror
*/
def staticModule(fullName: String): U#ModuleSymbol
@@ -119,4 +118,22 @@ abstract class Mirror[U <: Universe with Singleton] {
* @group Mirror
*/
def staticPackage(fullName: String): U#ModuleSymbol
+
+ /**
+ * Shortcut for `implicitly[WeakTypeTag[T]].tpe`
+ * @group TypeTags
+ */
+ def weakTypeOf[T: universe.WeakTypeTag]: U#Type = universe.weakTypeTag[T].in(this).tpe
+
+ /**
+ * Shortcut for `implicitly[TypeTag[T]].tpe`
+ * @group TypeTags
+ */
+ def typeOf[T: universe.TypeTag]: U#Type = universe.typeTag[T].in(this).tpe
+
+ /**
+ * Type symbol of `x` as derived from a type tag.
+ * @group TypeTags
+ */
+ def symbolOf[T: universe.WeakTypeTag]: U#TypeSymbol
}
diff --git a/src/reflect/scala/reflect/api/Mirrors.scala b/src/reflect/scala/reflect/api/Mirrors.scala
index 76a75940ff..ec420d184c 100644
--- a/src/reflect/scala/reflect/api/Mirrors.scala
+++ b/src/reflect/scala/reflect/api/Mirrors.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package api
/**
@@ -28,12 +29,12 @@ package api
* Compile-time `Mirror`s make use of only classloader `Mirror`s to load `Symbol`s
* by name.
*
- * The entry point to classloader `Mirror`s is via [[scala.reflect.macros.Context#mirror]].
+ * The entry point to classloader `Mirror`s is via [[scala.reflect.macros.blackbox.Context#mirror]] or [[scala.reflect.macros.whitebox.Context#mirror]].
* Typical methods which use classloader `Mirror`s include [[scala.reflect.api.Mirror#staticClass]],
* [[scala.reflect.api.Mirror#staticModule]], and [[scala.reflect.api.Mirror#staticPackage]]. For
* example:
* {{{
- * import scala.reflect.macros.Context
+ * import scala.reflect.macros.blackbox.Context
*
* case class Location(filename: String, line: Int, column: Int)
*
@@ -61,7 +62,7 @@ package api
* The entry point to `Mirror`s for use at runtime is via `ru.runtimeMirror(<classloader>)`, where
* `ru` is [[scala.reflect.runtime.universe]].
*
- * The result of a [[scala.reflect.api.JavaMirrors#runtimeMirror]] call is a classloader mirror,
+ * The result of a [[scala.reflect.api.JavaUniverse#runtimeMirror]] call is a classloader mirror,
* of type [[scala.reflect.api.Mirrors#ReflectiveMirror]], which can load symbols by names as
* discussed above (in the “Compile-time” section).
*
@@ -100,7 +101,7 @@ package api
* via `ModuleMirror.instance`). Entry point: `val mm = im.reflectMethod(<method symbol>)`.
* Example:
* {{{
- * scala> val methodX = typeOf[C].declaration(newTermName("x")).asMethod
+ * scala> val methodX = typeOf[C].declaration(TermName("x")).asMethod
* methodX: reflect.runtime.universe.MethodSymbol = method x
*
* scala> val mm = im.reflectMethod(methodX)
@@ -125,7 +126,7 @@ package api
* scala> val im = m.reflect(new C)
* im: reflect.runtime.universe.InstanceMirror = instance mirror for C@5f0c8ac1
*
- * scala> val fieldX = typeOf[C].declaration(newTermName("x")).asTerm.accessed.asTerm
+ * scala> val fieldX = typeOf[C].declaration(TermName("x")).asTerm.accessed.asTerm
* fieldX: reflect.runtime.universe.TermSymbol = value x
* scala> val fmX = im.reflectField(fieldX)
* fmX: reflect.runtime.universe.FieldMirror = field mirror for C.x (bound to C@5f0c8ac1)
@@ -135,7 +136,7 @@ package api
*
* scala> fmX.set(3) // NOTE: can set an underlying value of an immutable field!
*
- * scala> val fieldY = typeOf[C].declaration(newTermName("y")).asTerm.accessed.asTerm
+ * scala> val fieldY = typeOf[C].declaration(TermName("y")).asTerm.accessed.asTerm
* fieldY: reflect.runtime.universe.TermSymbol = variable y
*
* scala> val fmY = im.reflectField(fieldY)
@@ -152,7 +153,7 @@ package api
*
* '''[[scala.reflect.api.Mirrors#ClassMirror]]'''. Used for creating invoker mirrors for constructors.
* Entry points: for ''static classes'' `val cm1 = m.reflectClass(<class symbol>)`,
- * for ''inner classes'' `val mm2 = im.reflectClass(<module symbol>)`.
+ * for ''inner classes'' `val mm2 = im.reflectClass(<class symbol>)`.
* Example:
* {{{
* scala> case class C(x: Int)
@@ -224,7 +225,12 @@ trait Mirrors { self: Universe =>
/** Abstracts the runtime representation of a class on the underlying platform.
* @group Mirrors
*/
- type RuntimeClass >: Null
+ type RuntimeClass >: Null <: AnyRef
+
+ /** Has no special methods. Is here to provides erased identity for `RuntimeClass`.
+ * @group API
+ */
+ trait RuntimeClassApi
// todo. an improvement might be having mirrors reproduce the structure of the reflection domain
// e.g. a ClassMirror could also have a list of fields, methods, constructors and so on
@@ -254,8 +260,8 @@ trait Mirrors { self: Universe =>
* Note also that only accessor MethodMirrors, but not FieldMirrors will accurately reflect overriding behavior.
*
* To get a field symbol by the name of the field you would like to reflect,
- * use `<this mirror>.symbol.typeSignature.member(newTermName(<name of the field>)).asTerm.accessed`.
- * For further information about member lookup refer to `Symbol.typeSignature`.
+ * use `<this mirror>.symbol.info.member(TermName(<name of the field>)).asTerm.accessed`.
+ * For further information about member lookup refer to `Symbol.info`.
*
* The input symbol can be either private or non-private (Scala reflection transparently deals with visibility).
* It must be a member (declared or inherited) of the class of the instance underlying this mirror.
@@ -274,8 +280,8 @@ trait Mirrors { self: Universe =>
* that can be used to invoke the method provided.
*
* To get a method symbol by the name of the method you would like to reflect,
- * use `<this mirror>.symbol.typeSignature.member(newTermName(<name of the method>)).asMethod`.
- * For further information about member lookup refer to `Symbol.typeSignature`.
+ * use `<this mirror>.symbol.info.member(TermName(<name of the method>)).asMethod`.
+ * For further information about member lookup refer to `Symbol.info`.
*
* The input symbol can be either private or non-private (Scala reflection transparently deals with visibility).
* It must be a member (declared or inherited) of the instance underlying this mirror.
@@ -286,8 +292,8 @@ trait Mirrors { self: Universe =>
* that can be used to create instances of the class, inspect its companion object or perform further reflections.
*
* To get a class symbol by the name of the class you would like to reflect,
- * use `<this mirror>.symbol.typeSignature.member(newTypeName(<name of the class>)).asClass`.
- * For further information about member lookup refer to `Symbol.typeSignature`.
+ * use `<this mirror>.symbol.info.member(newTypeName(<name of the class>)).asClass`.
+ * For further information about member lookup refer to `Symbol.info`.
*
* The input symbol can be either private or non-private (Scala reflection transparently deals with visibility).
* It must be a member (declared or inherited) of the instance underlying this mirror.
@@ -298,8 +304,8 @@ trait Mirrors { self: Universe =>
* that can be used to get the instance of the object or inspect its companion class.
*
* To get a module symbol by the name of the object you would like to reflect,
- * use `<this mirror>.symbol.typeSignature.member(newTermName(<name of the object>)).asModule`.
- * For further information about member lookup refer to `Symbol.typeSignature`.
+ * use `<this mirror>.symbol.info.member(TermName(<name of the object>)).asModule`.
+ * For further information about member lookup refer to `Symbol.info`.
*
* The input symbol can be either private or non-private (Scala reflection transparently deals with visibility).
* It must be a member (declared or inherited) of the instance underlying this mirror.
@@ -350,6 +356,11 @@ trait Mirrors { self: Universe =>
* the value of the base field. To achieve overriding behavior, use reflectMethod on an accessor.
*/
def set(value: Any): Unit
+
+ /** Creates a new mirror which uses the same symbol, but is bound to a different receiver.
+ * This is significantly faster than recreating the mirror from scratch.
+ */
+ def bind(newReceiver: Any): FieldMirror
}
/** A mirror that reflects a method.
@@ -371,6 +382,11 @@ trait Mirrors { self: Universe =>
* with invoking the corresponding method or constructor.
*/
def apply(args: Any*): Any
+
+ /** Creates a new mirror which uses the same symbol, but is bound to a different receiver.
+ * This is significantly faster than recreating the mirror from scratch.
+ */
+ def bind(newReceiver: Any): MethodMirror
}
/** A mirror that reflects the instance or static parts of a runtime class.
@@ -421,8 +437,8 @@ trait Mirrors { self: Universe =>
* that can be used to invoke it and construct instances of this mirror's symbols.
*
* To get a constructor symbol you would like to reflect,
- * use `<this mirror>.symbol.typeSignature.member(nme.CONSTRUCTOR).asMethod`.
- * For further information about member lookup refer to `Symbol.typeSignature`.
+ * use `<this mirror>.symbol.info.member(termNames.CONSTRUCTOR).asMethod`.
+ * For further information about member lookup refer to `Symbol.info`.
*
* The input symbol can be either private or non-private (Scala reflection transparently deals with visibility).
* It must be a member (declared or inherited) of the class underlying this mirror.
@@ -488,7 +504,7 @@ trait Mirrors { self: Universe =>
/** A class symbol for the specified runtime class.
* @return The class symbol for the runtime class in the current class loader.
* @throws java.lang.ClassNotFoundException if no class with that name exists
- * @throws scala.reflect.internal.MissingRequirementError if no corresponding symbol exists
+ * @throws scala.reflect.ScalaReflectionException if no corresponding symbol exists
* to do: throws anything else?
*/
def classSymbol(rtcls: RuntimeClass): ClassSymbol
@@ -496,7 +512,7 @@ trait Mirrors { self: Universe =>
/** A module symbol for the specified runtime class.
* @return The module symbol for the runtime class in the current class loader.
* @throws java.lang.ClassNotFoundException if no class with that name exists
- * @throws scala.reflect.internal.MissingRequirementError if no corresponding symbol exists
+ * @throws scala.reflect.ScalaReflectionException if no corresponding symbol exists
* to do: throws anything else?
*/
def moduleSymbol(rtcls: RuntimeClass): ModuleSymbol
diff --git a/src/reflect/scala/reflect/api/Names.scala b/src/reflect/scala/reflect/api/Names.scala
index 7c12f180a8..fe5f47c25d 100644
--- a/src/reflect/scala/reflect/api/Names.scala
+++ b/src/reflect/scala/reflect/api/Names.scala
@@ -1,6 +1,9 @@
-package scala.reflect
+package scala
+package reflect
package api
+import scala.language.implicitConversions
+
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
@@ -30,55 +33,49 @@ trait Names {
* Enables an alternative notation `"map": TermName` as opposed to `newTermName("map")`.
* @group Names
*/
- implicit def stringToTermName(s: String): TermName = newTermName(s)
+ @deprecated("Use explicit `TermName(s)` instead", "2.11.0")
+ implicit def stringToTermName(s: String): TermName = TermName(s)
/** An implicit conversion from String to TypeName.
* Enables an alternative notation `"List": TypeName` as opposed to `newTypeName("List")`.
* @group Names
*/
- implicit def stringToTypeName(s: String): TypeName = newTypeName(s)
+ @deprecated("Use explicit `TypeName(s)` instead", "2.11.0")
+ implicit def stringToTypeName(s: String): TypeName = TypeName(s)
/** The abstract type of names.
* @group Names
*/
- type Name >: Null <: NameApi
-
- /** A tag that preserves the identity of the `Name` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val NameTag: ClassTag[Name]
+ type Name >: Null <: AnyRef with NameApi
/** The abstract type of names representing terms.
* @group Names
*/
- type TypeName >: Null <: Name
+ type TypeName >: Null <: TypeNameApi with Name
- /** A tag that preserves the identity of the `TypeName` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
+ /** Has no special methods. Is here to provides erased identity for `TypeName`.
+ * @group API
*/
-implicit val TypeNameTag: ClassTag[TypeName]
+ trait TypeNameApi
/** The abstract type of names representing types.
* @group Names
*/
- type TermName >: Null <: Name
+ type TermName >: Null <: TermNameApi with Name
- /** A tag that preserves the identity of the `TermName` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
+ /** Has no special methods. Is here to provides erased identity for `TermName`.
+ * @group API
*/
- implicit val TermNameTag: ClassTag[TermName]
+ trait TermNameApi
/** The API of Name instances.
* @group API
*/
abstract class NameApi {
- /** Checks wether the name is a a term name */
+ /** Checks wether the name is a term name */
def isTermName: Boolean
- /** Checks wether the name is a a type name */
+ /** Checks wether the name is a type name */
def isTypeName: Boolean
/** Returns a term name that wraps the same string as `this` */
@@ -90,11 +87,13 @@ implicit val TypeNameTag: ClassTag[TypeName]
/** Replaces all occurrences of \$op_names in this name by corresponding operator symbols.
* Example: `foo_\$plus\$eq` becomes `foo_+=`
*/
+ @deprecated("Use `decodedName.toString` instead", "2.11.0")
def decoded: String
/** Replaces all occurrences of operator symbols in this name by corresponding \$op_names.
* Example: `foo_+=` becomes `foo_\$plus\$eq`.
*/
+ @deprecated("Use `encodedName.toString` instead", "2.11.0")
def encoded: String
/** The decoded name, still represented as a name.
@@ -109,10 +108,38 @@ implicit val TypeNameTag: ClassTag[TypeName]
/** Create a new term name.
* @group Names
*/
+ @deprecated("Use TermName instead", "2.11.0")
def newTermName(s: String): TermName
/** Creates a new type name.
* @group Names
*/
+ @deprecated("Use TypeName instead", "2.11.0")
def newTypeName(s: String): TypeName
+
+ /** The constructor/extractor for `TermName` instances.
+ * @group Extractors
+ */
+ val TermName: TermNameExtractor
+
+ /** An extractor class to create and pattern match with syntax `TermName(s)`.
+ * @group Extractors
+ */
+ abstract class TermNameExtractor {
+ def apply(s: String): TermName
+ def unapply(name: TermName): Option[String]
+ }
+
+ /** The constructor/extractor for `TypeName` instances.
+ * @group Extractors
+ */
+ val TypeName: TypeNameExtractor
+
+ /** An extractor class to create and pattern match with syntax `TypeName(s)`.
+ * @group Extractors
+ */
+ abstract class TypeNameExtractor {
+ def apply(s: String): TypeName
+ def unapply(name: TypeName): Option[String]
+ }
}
diff --git a/src/reflect/scala/reflect/api/Position.scala b/src/reflect/scala/reflect/api/Position.scala
index 63c67627a3..9d1b7c3812 100644
--- a/src/reflect/scala/reflect/api/Position.scala
+++ b/src/reflect/scala/reflect/api/Position.scala
@@ -1,17 +1,52 @@
-package scala.reflect
+package scala
+package reflect
package api
import scala.reflect.macros.Attachments
/**
- * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
+ * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * Position tracks the origin of [[Symbols#Symbol symbols]] and [[Trees#Tree tree nodes]]. They are commonly used when
- * displaying warnings and errors, to indicate the incorrect point in the program.
+ * Position tracks the origin of [[Symbols#Symbol symbols]] and [[Trees#Tree tree nodes]]. They are commonly used when
+ * displaying warnings and errors, to indicate the incorrect point in the program.
*
- * <b>Please note that this trait may be refactored in future versions of the Scala reflection API.</b>
+ * Every non-empty position refers to a SourceFile and three character
+ * offsets within it: start, end, and point. The point is where the ^ belongs when
+ * issuing an error message, usually a Name. A range position can be designated
+ * as transparent, which excuses it from maintaining the invariants to follow. If
+ * a transparent position has opaque children, those are considered as if they were
+ * the direct children of the transparent position's parent.
*
- * For more information about `Position`s, see the [[http://docs.scala-lang.org/overviews/reflection/annotations-names-scopes.html Reflection Guide: Annotations, Names, Scopes, and More]]
+ * Note: some of these invariants actually apply to the trees which carry
+ * the positions, but they are phrased as if the positions themselves were
+ * the parent/children for conciseness.
+ *
+ * Invariant 1: in a focused/offset position, start == point == end
+ * Invariant 2: in a range position, start <= point < end
+ * Invariant 3: an offset position never has a child with a range position
+ * Invariant 4: every range position child of a range position parent is contained within its parent
+ * Invariant 5: opaque range position siblings overlap at most at a single point
+ *
+ * The following tests are useful on positions:
+ *
+ * pos.isDefined true if position is not an UndefinedPosition (those being NoPosition and FakePos)
+ * pos.isRange true if position is a range (opaque or transparent) which implies start < end
+ * pos.isOpaqueRange true if position is an opaque range
+ *
+ * The following accessor methods are provided - an exception will be thrown if
+ * point/start/end are attempted on an UndefinedPosition.
+ *
+ * pos.source The source file of the position, or NoSourceFile if unavailable
+ * pos.point The offset of the point
+ * pos.start The (inclusive) start offset, or the point of an offset position
+ * pos.end The (exclusive) end offset, or the point of an offset position
+ *
+ * The following conversion methods are often used:
+ *
+ * pos.focus Converts a range position to an offset position focused on the point
+ * pos.makeTransparent Convert an opaque range into a transparent range
+ *
+ * For more information about `Position`s, see the [[http://docs.scala-lang.org/overviews/reflection/annotations-names-scopes.html Reflection Guide: Annotations, Names, Scopes, and More]]
*
* @groupname Common Commonly used methods
* @group ReflectionAPI
@@ -19,23 +54,9 @@ import scala.reflect.macros.Attachments
trait Position extends Attachments {
/** @inheritdoc */
- type Pos >: Null <: Position
+ type Pos >: Null <: AnyRef with Position
- /** Java file corresponding to the source file of this position.
- *
- * The return type is `scala.reflect.io.AbstractFile`, which belongs to an experimental part of Scala reflection.
- * It should not be used unless you know what you are doing. In subsequent releases, this API will be refined
- * and exposed as a part of scala.reflect.api.
- *
- * @group Common
- */
- def source: scala.reflect.internal.util.SourceFile
-
- /** Is this position neither a NoPosition nor a FakePosition?
- * If isDefined is true, offset and source are both defined.
- * @group Common
- */
- def isDefined: Boolean
+ ////////////////// POSITION FLAVORS //////////////////
/** Is this position a range position? */
def isRange: Boolean
@@ -46,14 +67,18 @@ trait Position extends Attachments {
/** Is this position a non-transparent range position? */
def isOpaqueRange: Boolean
+ /** If this is a range position, the offset position of its point.
+ * Otherwise the position itself
+ */
+ def focus: Pos
+
/** 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
+ ////////////////// POSITION ESSENTIALS //////////////////
- /** The start of the position's range, or point if not a range position. */
- def startOrPoint: Int
+ /** The start of the position's range, or the point if not a range position. */
+ def start: Int
/** The point (where the ^ is) of the position, which is easiest to access using the [[line]] and [[column]] values.
* The [[lineContent line content]] is also available.
@@ -61,104 +86,122 @@ trait Position extends Attachments {
*/
def point: Int
- /** The point (where the ^ is) of the position, or else `default` if undefined.
+ /** The end of the position's range, or the point if not a range position.
+ */
+ def end: Int
+
+ /** Java file corresponding to the source file of this position.
+ *
+ * The return type is `scala.reflect.io.AbstractFile`, which belongs to an experimental part of Scala reflection.
+ * It should not be used unless you know what you are doing. In subsequent releases, this API will be refined
+ * and exposed as a part of scala.reflect.api.
+ *
* @group Common
*/
- def pointOrElse(default: Int): Int
+ def source: scala.reflect.internal.util.SourceFile
- /** The end of the position's range, error if not a range position.
+ /** The position indicates a [[column `column`]] and the `line` in the source file.
+ * @group Common
*/
- def end: Int
+ def line: Int
- /** The end of the position's range, or point if not a range position.
+ /** The position indicates a `column` and the [[line `line`]] in the source file.
+ * @group Common
*/
- def endOrPoint: Int
+ def column: Int
+
+ ////////////////// POSITION FACTORIES //////////////////
- /** The same position with a different start value (if a range).
+ /** Returns a new position with the same attributes, but a different start value (if a range).
*/
def withStart(off: Int): Pos
- /** The same position with a different end value (if a range).
+ /** Returns a new position with the same attributes, but 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).
+ /** Returns a new position with the same attributes, but 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
+ ////////////////// STUFF //////////////////
+
+ /** Is this position not a NoPosition?
+ * If isDefined is true, offset and source are both defined.
+ * @group Common
*/
- def union(pos: Pos): Pos
+ @deprecated("Removed from the public API", "2.11.0") def isDefined: Boolean
- /** If this is a range position, the offset position of its point.
- * Otherwise the position itself
+ /** The point (where the ^ is) of the position, or else `default` if undefined.
+ * @group Common
*/
- def focus: Pos
+ @deprecated("Removed from the public API", "2.11.0") def pointOrElse(default: Int): Int
+
+ /** The start of the position's range, or point if not a range position. */
+ @deprecated("Removed from the public API", "2.11.0") def startOrPoint: Int
+
+ /** The end of the position's range, or point if not a range position.
+ */
+ @deprecated("Removed from the public API", "2.11.0") def endOrPoint: Int
+
+ /** If this is a range, the union with the other range, with the point of this position.
+ * Otherwise, this position
+ */
+ @deprecated("Removed from the public API", "2.11.0") def union(pos: Pos): Pos
/** If this is a range position, the offset position of its start.
* Otherwise the position itself
*/
- def focusStart: Pos
+ @deprecated("Removed from the public API", "2.11.0") def focusStart: Pos
/** If this is a range position, the offset position of its end.
* Otherwise the position itself
*/
- def focusEnd: Pos
+ @deprecated("Removed from the public API", "2.11.0") 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
+ @deprecated("Removed from the public API", "2.11.0") 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
+ @deprecated("Removed from the public API", "2.11.0") 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
+ @deprecated("Removed from the public API", "2.11.0") 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
+ @deprecated("Removed from the public API", "2.11.0") 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
+ @deprecated("Removed from the public API", "2.11.0") 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
-
- /** The position indicates a [[column `column`]] and the `line` in the source file.
- * @group Common
- */
- def line: Int
-
- /** The position indicates a `column` and the [[line `line`]] in the source file.
- * @group Common
- */
- def column: Int
+ @deprecated("Removed from the public API", "2.11.0") def sameRange(pos: Pos): Boolean
/** Convert this to a position around `point` that spans a single source line
*/
- def toSingleLine: Pos
+ @deprecated("Removed from the public API", "2.11.0") def toSingleLine: Pos
/** The content of the line this Position refers to.
* @group Common
*/
- def lineContent: String
+ @deprecated("Removed from the public API", "2.11.0") def lineContent: String
/** Show a textual representation of the position.
*/
- def show: String
+ @deprecated("Use `universe.show(position)` instead", "2.11.0") def show: String
}
diff --git a/src/reflect/scala/reflect/api/Positions.scala b/src/reflect/scala/reflect/api/Positions.scala
index 87f00fdb88..63ad605656 100644
--- a/src/reflect/scala/reflect/api/Positions.scala
+++ b/src/reflect/scala/reflect/api/Positions.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package api
/**
@@ -18,13 +19,7 @@ trait Positions {
* The main documentation entry about positions is located at [[scala.reflect.api.Position]].
* @group Positions
*/
- type Position >: Null <: scala.reflect.api.Position { type Pos = Position }
-
- /** A tag that preserves the identity of the `Position` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val PositionTag: ClassTag[Position]
+ type Position >: Null <: AnyRef with scala.reflect.api.Position { type Pos = Position }
/** A special "missing" position.
* @group Positions
diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala
index 85ddcc6523..92ae6d8b44 100644
--- a/src/reflect/scala/reflect/api/Printers.scala
+++ b/src/reflect/scala/reflect/api/Printers.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package api
import java.io.{ PrintWriter, StringWriter }
@@ -47,7 +48,7 @@ import java.io.{ PrintWriter, StringWriter }
* res1: String = Block(List(
* ClassDef(Modifiers(FINAL), newTypeName("C"), List(), Template(
* List(Ident(newTypeName("AnyRef"))),
- * emptyValDef,
+ * noSelfType,
* List(
* DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(),
* Block(List(
@@ -67,11 +68,11 @@ import java.io.{ PrintWriter, StringWriter }
* scala> import scala.reflect.runtime.{currentMirror => cm}
* import scala.reflect.runtime.{currentMirror=>cm}
*
- * scala> showRaw(cm.mkToolBox().typeCheck(tree), printTypes = true)
+ * scala> showRaw(cm.mkToolBox().typecheck(tree), printTypes = true)
* res2: String = Block[1](List(
* ClassDef[2](Modifiers(FINAL), newTypeName("C"), List(), Template[3](
* List(Ident[4](newTypeName("AnyRef"))),
- * emptyValDef,
+ * noSelfType,
* List(
* DefDef[2](Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree[3](),
* Block[1](List(
@@ -141,66 +142,97 @@ trait Printers { self: Universe =>
def print(args: Any*)
protected var printTypes = false
protected var printIds = false
+ protected var printOwners = false
protected var printKinds = false
protected var printMirrors = false
+ protected var printPositions = false
def withTypes: this.type = { printTypes = true; this }
def withoutTypes: this.type = { printTypes = false; this }
def withIds: this.type = { printIds = true; this }
def withoutIds: this.type = { printIds = false; this }
+ def withOwners: this.type = { printOwners = true; this }
+ def withoutOwners: this.type = { printOwners = false; this }
def withKinds: this.type = { printKinds = true; this }
def withoutKinds: this.type = { printKinds = false; this }
def withMirrors: this.type = { printMirrors = true; this }
def withoutMirrors: this.type = { printMirrors = false; this }
+ def withPositions: this.type = { printPositions = true; this }
+ def withoutPositions: this.type = { printPositions = false; this }
}
/** @group Printers */
- case class BooleanFlag(val value: Option[Boolean])
+ case class BooleanFlag(value: Option[Boolean])
/** @group Printers */
object BooleanFlag {
import scala.language.implicitConversions
implicit def booleanToBooleanFlag(value: Boolean): BooleanFlag = BooleanFlag(Some(value))
implicit def optionToBooleanFlag(value: Option[Boolean]): BooleanFlag = BooleanFlag(value)
+ import scala.reflect.internal.settings.MutableSettings
+ implicit def settingToBooleanFlag(setting: MutableSettings#BooleanSetting): BooleanFlag = BooleanFlag(Some(setting.value))
}
/** @group Printers */
- protected def render(what: Any, mkPrinter: PrintWriter => TreePrinter, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None): String = {
+ protected def render(what: Any, mkPrinter: PrintWriter => TreePrinter, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printOwners: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String = {
val buffer = new StringWriter()
val writer = new PrintWriter(buffer)
- var printer = mkPrinter(writer)
+ val printer = mkPrinter(writer)
printTypes.value.map(printTypes => if (printTypes) printer.withTypes else printer.withoutTypes)
printIds.value.map(printIds => if (printIds) printer.withIds else printer.withoutIds)
+ printOwners.value.map(printOwners => if (printOwners) printer.withOwners else printer.withoutOwners)
printKinds.value.map(printKinds => if (printKinds) printer.withKinds else printer.withoutKinds)
printMirrors.value.map(printMirrors => if (printMirrors) printer.withMirrors else printer.withoutMirrors)
+ printPositions.value.map(printPositions => if (printPositions) printer.withPositions else printer.withoutPositions)
printer.print(what)
writer.flush()
buffer.toString
}
/** By default trees are printed with `show`
- * @group Printers
+ * @group Printers
*/
override protected def treeToString(tree: Tree) = show(tree)
/** Renders a representation of a reflection artifact
- * as desugared Java code.
+ * as desugared Scala code.
*
- * @group Printers
+ * @group Printers
*/
- def show(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None): String =
- render(any, newTreePrinter(_), printTypes, printIds, printKinds, printMirrors)
+ def show(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printOwners: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String =
+ render(any, newTreePrinter(_), printTypes, printIds, printOwners, printKinds, printMirrors, printPositions)
/** Hook to define what `show(...)` means.
* @group Printers
*/
protected def newTreePrinter(out: PrintWriter): TreePrinter
- /** Renders internal structure of a reflection artifact as the
- * visualization of a Scala syntax tree.
+ /**
+ * Renders the code of the passed tree, so that:
+ * 1) it can be later compiled by scalac retaining the same meaning,
+ * 2) it looks pretty.
+ * #1 is available for unattributed trees and attributed trees
+ * #2 is more or less okay indentation-wise, but at the moment there's a lot of desugaring
+ * left in place, and that's what we plan to improve in the future.
+ * printTypes, printIds, printPositions options have the same meaning as for TreePrinter
+ * printRootPkg option is available only for attributed trees.
*
+ * @group Printers
+ */
+ def showCode(tree: Tree, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printOwners: BooleanFlag = None, printPositions: BooleanFlag = None, printRootPkg: Boolean = false) =
+ render(tree, newCodePrinter(_, tree, printRootPkg), printTypes, printIds, printOwners, printKinds = None, printMirrors = None, printPositions)
+
+ /**
+ * Hook to define what `showCode(...)` means.
* @group Printers
*/
- def showRaw(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None): String =
- render(any, newRawTreePrinter(_), printTypes, printIds, printKinds, printMirrors)
+ protected def newCodePrinter(out: PrintWriter, tree: Tree, printRootPkg: Boolean): TreePrinter
+
+ /** Renders internal structure of a reflection artifact as the
+ * visualization of a Scala syntax tree.
+ *
+ * @group Printers
+ */
+ def showRaw(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printOwners: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String =
+ render(any, newRawTreePrinter(_), printTypes, printIds, printOwners, printKinds, printMirrors, printPositions)
/** Hook to define what `showRaw(...)` means.
* @group Printers
@@ -222,8 +254,23 @@ trait Printers { self: Universe =>
*/
def show(flags: FlagSet): String
+ /** Renders a prettified representation of a position.
+ * @group Printers
+ */
+ def show(position: Position): String
+
/** Renders internal structure of a flag set.
* @group Printers
*/
def showRaw(flags: FlagSet): String = flags.toString
+
+ /** Renders internal structure of a position.
+ * @group Printers
+ */
+ def showRaw(position: Position): String = position.toString
+
+ /** Renders a string that represents a declaration of this symbol written in Scala.
+ * @group Printers
+ */
+ def showDecl(sym: Symbol): String
}
diff --git a/src/reflect/scala/reflect/api/Quasiquotes.scala b/src/reflect/scala/reflect/api/Quasiquotes.scala
new file mode 100644
index 0000000000..e905aa4153
--- /dev/null
+++ b/src/reflect/scala/reflect/api/Quasiquotes.scala
@@ -0,0 +1,25 @@
+package scala.reflect
+package api
+
+trait Quasiquotes { self: Universe =>
+
+ /** Implicit class that introduces `q`, `tq`, `cq,` `p` and `fq` string interpolators
+ * that are also known as quasiquotes. With their help you can easily manipulate
+ * Scala reflection ASTs.
+ *
+ * @see [[http://docs.scala-lang.org/overviews/quasiquotes/intro.html]]
+ */
+ implicit class Quasiquote(ctx: StringContext) {
+ protected trait api {
+ // implementation is hardwired to `dispatch` method of `scala.tools.reflect.quasiquotes.Quasiquotes`
+ // using the mechanism implemented in `scala.tools.reflect.FastTrack`
+ def apply[T](args: T*): Tree = macro ???
+ def unapply(scrutinee: Any): Any = macro ???
+ }
+ object q extends api
+ object tq extends api
+ object cq extends api
+ object pq extends api
+ object fq extends api
+ }
+}
diff --git a/src/reflect/scala/reflect/api/Scopes.scala b/src/reflect/scala/reflect/api/Scopes.scala
index 7f9799393c..c9142fba47 100644
--- a/src/reflect/scala/reflect/api/Scopes.scala
+++ b/src/reflect/scala/reflect/api/Scopes.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package api
/**
@@ -15,7 +16,7 @@ package api
* there is the `newScopeWith` function.
*
* Additional functionality is exposed in member scopes that are returned by
- * `members` and `declarations` defined in [[scala.reflect.api.Types#TypeApi]].
+ * `members` and `decls` defined in [[scala.reflect.api.Types#TypeApi]].
* Such scopes support the `sorted` method, which sorts members in declaration order.
*
* @group ReflectionAPI
@@ -26,29 +27,18 @@ trait Scopes { self: Universe =>
* @template
* @group Scopes
*/
- type Scope >: Null <: ScopeApi
+ type Scope >: Null <: AnyRef with ScopeApi
/** The API that all scopes support
* @group API
*/
trait ScopeApi extends Iterable[Symbol]
- /** A tag that preserves the identity of the `Scope` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ScopeTag: ClassTag[Scope]
-
- /** Create a new scope with the given initial elements.
- * @group Scopes
- */
- def newScopeWith(elems: Symbol*): Scope
-
/** The type of member scopes, as in class definitions, for example.
* @template
* @group Scopes
*/
- type MemberScope >: Null <: Scope with MemberScopeApi
+ type MemberScope >: Null <: AnyRef with MemberScopeApi with Scope
/** The API that all member scopes support
* @group API
@@ -61,10 +51,4 @@ trait Scopes { self: Universe =>
*/
def sorted: List[Symbol]
}
-
- /** A tag that preserves the identity of the `MemberScope` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val MemberScopeTag: ClassTag[MemberScope]
-} \ No newline at end of file
+}
diff --git a/src/reflect/scala/reflect/api/StandardDefinitions.scala b/src/reflect/scala/reflect/api/StandardDefinitions.scala
index 721b0bc7f2..524b7ea14b 100644
--- a/src/reflect/scala/reflect/api/StandardDefinitions.scala
+++ b/src/reflect/scala/reflect/api/StandardDefinitions.scala
@@ -2,7 +2,8 @@
* Copyright 2005-2013 LAMP/EPFL
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package api
/**
@@ -130,10 +131,10 @@ trait StandardDefinitions {
* scala> val m = typeOf[C].member(newTermName("m")).asMethod
* m: reflect.runtime.universe.MethodSymbol = method m
*
- * scala> m.params(0)(0).typeSignature
+ * scala> m.params(0)(0).info
* res1: reflect.runtime.universe.Type = => scala.Int
*
- * scala> showRaw(m.params(0)(0).typeSignature)
+ * scala> showRaw(m.params(0)(0).info)
* res2: String = TypeRef(
* ThisType(scala),
* scala.<byname>, // <-- ByNameParamClass
@@ -158,10 +159,10 @@ trait StandardDefinitions {
* scala> val m = typeOf[C].member(newTermName("m")).asMethod
* m: reflect.runtime.universe.MethodSymbol = method m
*
- * scala> m.params(0)(0).typeSignature
+ * scala> m.params(0)(0).info
* res1: reflect.runtime.universe.Type = <repeated...>[Object]
*
- * scala> showRaw(m.params(0)(0).typeSignature)
+ * scala> showRaw(m.params(0)(0).info)
* res2: String = TypeRef(
* ThisType(scala),
* scala.<repeated...>, // <-- JavaRepeatedParamClass
@@ -183,10 +184,10 @@ trait StandardDefinitions {
* scala> val m = typeOf[C].member(newTermName("m")).asMethod
* m: reflect.runtime.universe.MethodSymbol = method m
*
- * scala> m.params(0)(0).typeSignature
+ * scala> m.params(0)(0).info
* res1: reflect.runtime.universe.Type = scala.Int*
*
- * scala> showRaw(m.params(0)(0).typeSignature)
+ * scala> showRaw(m.params(0)(0).info)
* res2: String = TypeRef(
* ThisType(scala),
* scala.<repeated>, // <-- RepeatedParamClass
@@ -213,29 +214,43 @@ trait StandardDefinitions {
/** The module symbol of module `scala.Some`. */
def SomeModule: ModuleSymbol
- /** The array of class symbols for classes `scala.ProductX`.
+ /** Function-like api that lets you acess symbol
+ * of the definition with given arity and also look
+ * through all known symbols via `seq`.
+ */
+ abstract class VarArityClassApi extends (Int => Symbol) {
+ def seq: Seq[ClassSymbol]
+ }
+
+ /** Function-like object that maps arity to symbols for classes `scala.ProductX`.
* - 0th element is `Unit`
* - 1st element is `Product1`
* - ...
* - 22nd element is `Product22`
+ * - 23nd element is `NoSymbol`
+ * - ...
*/
- def ProductClass : Array[ClassSymbol]
+ def ProductClass: VarArityClassApi
- /** The array of class symbols for classes `scala.FunctionX`.
+ /** Function-like object that maps arity to symbols for classes `scala.FunctionX`.
* - 0th element is `Function0`
* - 1st element is `Function1`
* - ...
* - 22nd element is `Function22`
+ * - 23nd element is `NoSymbol`
+ * - ...
*/
- def FunctionClass : Array[ClassSymbol]
+ def FunctionClass: VarArityClassApi
- /** The array of class symbols for classes `scala.TupleX`.
+ /** Function-like object that maps arity to symbols for classes `scala.TupleX`.
* - 0th element is `NoSymbol`
- * - 1st element is `Product1`
+ * - 1st element is `Tuple1`
* - ...
- * - 22nd element is `Product22`
+ * - 22nd element is `Tuple22`
+ * - 23nd element is `NoSymbol`
+ * - ...
*/
- def TupleClass: Array[Symbol] // cannot make it Array[ClassSymbol], because TupleClass(0) is supposed to be NoSymbol. weird
+ def TupleClass: VarArityClassApi
/** Contains Scala primitive value classes:
* - Byte
diff --git a/src/reflect/scala/reflect/api/StandardLiftables.scala b/src/reflect/scala/reflect/api/StandardLiftables.scala
new file mode 100644
index 0000000000..66ac62cc9e
--- /dev/null
+++ b/src/reflect/scala/reflect/api/StandardLiftables.scala
@@ -0,0 +1,235 @@
+package scala.reflect
+package api
+
+trait StandardLiftables { self: Universe =>
+ import internal._
+ import reificationSupport.{SyntacticTuple, ScalaDot}
+
+ trait StandardLiftableInstances {
+ private def lift[T: Liftable](value: T): Tree = implicitly[Liftable[T]].apply(value)
+ private def selectScala(names: Name*) = names.tail.foldLeft(ScalaDot(names.head)) { Select(_, _) }
+ private def callScala(names: Name*)(args: List[Tree]) = Apply(selectScala(names: _*), args)
+ private def callCollection(name: Name)(args: List[Tree]) = callScala(stdnme.collection, stdnme.immutable, name)(args)
+ private def liftAsLiteral[T]: Liftable[T] = Liftable { v => Literal(Constant(v)) }
+
+ implicit def liftByte[T <: Byte]: Liftable[T] = liftAsLiteral[T]
+ implicit def liftShort[T <: Short]: Liftable[T] = liftAsLiteral[T]
+ implicit def liftChar[T <: Char]: Liftable[T] = liftAsLiteral[T]
+ implicit def liftInt[T <: Int]: Liftable[T] = liftAsLiteral[T]
+ implicit def liftLong[T <: Long]: Liftable[T] = liftAsLiteral[T]
+ implicit def liftFloat[T <: Float]: Liftable[T] = liftAsLiteral[T]
+ implicit def liftDouble[T <: Double]: Liftable[T] = liftAsLiteral[T]
+ implicit def liftBoolean[T <: Boolean]: Liftable[T] = liftAsLiteral[T]
+ implicit def liftUnit: Liftable[Unit] = liftAsLiteral[Unit]
+ implicit def liftString[T <: String]: Liftable[T] = liftAsLiteral[T]
+
+ implicit def liftScalaSymbol: Liftable[scala.Symbol] = Liftable { v =>
+ callScala(stdnme.Symbol)(Literal(Constant(v.name)) :: Nil)
+ }
+
+ implicit def liftTree[T <: Tree]: Liftable[T] = Liftable { identity }
+ implicit def liftName[T <: Name]: Liftable[T] = Liftable { name => Ident(name) }
+ implicit def liftExpr[T <: Expr[_]]: Liftable[T] = Liftable { expr => expr.tree }
+ implicit def liftType[T <: Type]: Liftable[T] = Liftable { tpe => TypeTree(tpe) }
+ implicit def liftTypeTag[T <: WeakTypeTag[_]]: Liftable[T] = Liftable { ttag => TypeTree(ttag.tpe) }
+ implicit def liftConstant[T <: Constant]: Liftable[T] = Liftable { const => Literal(const) }
+
+ implicit def liftArray[T: Liftable]: Liftable[Array[T]] = Liftable { arr => callScala(stdnme.Array)(arr.map(lift(_)).toList) }
+ implicit def liftVector[T: Liftable]: Liftable[Vector[T]] = Liftable { vect => callCollection(stdnme.Vector)(vect.map(lift(_)).toList) }
+ implicit def liftList[T: Liftable]: Liftable[List[T]] = Liftable { lst => callCollection(stdnme.List)(lst.map(lift(_))) }
+ implicit def liftNil: Liftable[Nil.type] = Liftable { _ => selectScala(stdnme.collection, stdnme.immutable, stdnme.Nil) }
+ implicit def liftMap[K: Liftable, V: Liftable]: Liftable[Map[K, V]] = Liftable { m => callCollection(stdnme.Map)(m.toList.map(lift(_))) }
+ implicit def liftSet[T: Liftable]: Liftable[Set[T]] = Liftable { s => callCollection(stdnme.Set)(s.toList.map(lift(_))) }
+
+ implicit def liftSome[T: Liftable]: Liftable[Some[T]] = Liftable { case Some(v) => callScala(stdnme.Some)(lift(v) :: Nil) }
+ implicit def liftNone: Liftable[None.type] = Liftable { _ => selectScala(stdnme.None) }
+ implicit def liftOption[T: Liftable]: Liftable[Option[T]] = Liftable {
+ case some: Some[T] => lift(some)
+ case none: None.type => lift(none)
+ }
+
+ implicit def liftLeft[L: Liftable, R]: Liftable[Left[L, R]] = Liftable { case Left(v) => callScala(stdnme.util, stdnme.Left)(lift(v) :: Nil) }
+ implicit def liftRight[L, R: Liftable]: Liftable[Right[L, R]] = Liftable { case Right(v) => callScala(stdnme.util, stdnme.Right)(lift(v) :: Nil) }
+ implicit def liftEither[L: Liftable, R: Liftable]: Liftable[Either[L, R]] = Liftable {
+ case left: Left[L, R] => lift(left)
+ case right: Right[L, R] => lift(right)
+ }
+
+ implicit def liftTuple2[T1, T2](implicit liftT1: Liftable[T1], liftT2: Liftable[T2]): Liftable[Tuple2[T1, T2]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: Nil)
+ }
+ implicit def liftTuple3[T1, T2, T3](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3]): Liftable[Tuple3[T1, T2, T3]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: Nil)
+ }
+ implicit def liftTuple4[T1, T2, T3, T4](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4]): Liftable[Tuple4[T1, T2, T3, T4]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: Nil)
+ }
+ implicit def liftTuple5[T1, T2, T3, T4, T5](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5]): Liftable[Tuple5[T1, T2, T3, T4, T5]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: Nil)
+ }
+ implicit def liftTuple6[T1, T2, T3, T4, T5, T6](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5], liftT6: Liftable[T6]): Liftable[Tuple6[T1, T2, T3, T4, T5, T6]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: Nil)
+ }
+ implicit def liftTuple7[T1, T2, T3, T4, T5, T6, T7](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5], liftT6: Liftable[T6], liftT7: Liftable[T7]): Liftable[Tuple7[T1, T2, T3, T4, T5, T6, T7]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: liftT7(t._7) :: Nil)
+ }
+ implicit def liftTuple8[T1, T2, T3, T4, T5, T6, T7, T8](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5], liftT6: Liftable[T6], liftT7: Liftable[T7], liftT8: Liftable[T8]): Liftable[Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: liftT7(t._7) :: liftT8(t._8) :: Nil)
+ }
+ implicit def liftTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5], liftT6: Liftable[T6], liftT7: Liftable[T7], liftT8: Liftable[T8], liftT9: Liftable[T9]): Liftable[Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: liftT7(t._7) :: liftT8(t._8) :: liftT9(t._9) :: Nil)
+ }
+ implicit def liftTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5], liftT6: Liftable[T6], liftT7: Liftable[T7], liftT8: Liftable[T8], liftT9: Liftable[T9], liftT10: Liftable[T10]): Liftable[Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: liftT7(t._7) :: liftT8(t._8) :: liftT9(t._9) :: liftT10(t._10) :: Nil)
+ }
+ implicit def liftTuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5], liftT6: Liftable[T6], liftT7: Liftable[T7], liftT8: Liftable[T8], liftT9: Liftable[T9], liftT10: Liftable[T10], liftT11: Liftable[T11]): Liftable[Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: liftT7(t._7) :: liftT8(t._8) :: liftT9(t._9) :: liftT10(t._10) :: liftT11(t._11) :: Nil)
+ }
+ implicit def liftTuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5], liftT6: Liftable[T6], liftT7: Liftable[T7], liftT8: Liftable[T8], liftT9: Liftable[T9], liftT10: Liftable[T10], liftT11: Liftable[T11], liftT12: Liftable[T12]): Liftable[Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: liftT7(t._7) :: liftT8(t._8) :: liftT9(t._9) :: liftT10(t._10) :: liftT11(t._11) :: liftT12(t._12) :: Nil)
+ }
+ implicit def liftTuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5], liftT6: Liftable[T6], liftT7: Liftable[T7], liftT8: Liftable[T8], liftT9: Liftable[T9], liftT10: Liftable[T10], liftT11: Liftable[T11], liftT12: Liftable[T12], liftT13: Liftable[T13]): Liftable[Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: liftT7(t._7) :: liftT8(t._8) :: liftT9(t._9) :: liftT10(t._10) :: liftT11(t._11) :: liftT12(t._12) :: liftT13(t._13) :: Nil)
+ }
+ implicit def liftTuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5], liftT6: Liftable[T6], liftT7: Liftable[T7], liftT8: Liftable[T8], liftT9: Liftable[T9], liftT10: Liftable[T10], liftT11: Liftable[T11], liftT12: Liftable[T12], liftT13: Liftable[T13], liftT14: Liftable[T14]): Liftable[Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: liftT7(t._7) :: liftT8(t._8) :: liftT9(t._9) :: liftT10(t._10) :: liftT11(t._11) :: liftT12(t._12) :: liftT13(t._13) :: liftT14(t._14) :: Nil)
+ }
+ implicit def liftTuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5], liftT6: Liftable[T6], liftT7: Liftable[T7], liftT8: Liftable[T8], liftT9: Liftable[T9], liftT10: Liftable[T10], liftT11: Liftable[T11], liftT12: Liftable[T12], liftT13: Liftable[T13], liftT14: Liftable[T14], liftT15: Liftable[T15]): Liftable[Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: liftT7(t._7) :: liftT8(t._8) :: liftT9(t._9) :: liftT10(t._10) :: liftT11(t._11) :: liftT12(t._12) :: liftT13(t._13) :: liftT14(t._14) :: liftT15(t._15) :: Nil)
+ }
+ implicit def liftTuple16[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5], liftT6: Liftable[T6], liftT7: Liftable[T7], liftT8: Liftable[T8], liftT9: Liftable[T9], liftT10: Liftable[T10], liftT11: Liftable[T11], liftT12: Liftable[T12], liftT13: Liftable[T13], liftT14: Liftable[T14], liftT15: Liftable[T15], liftT16: Liftable[T16]): Liftable[Tuple16[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: liftT7(t._7) :: liftT8(t._8) :: liftT9(t._9) :: liftT10(t._10) :: liftT11(t._11) :: liftT12(t._12) :: liftT13(t._13) :: liftT14(t._14) :: liftT15(t._15) :: liftT16(t._16) :: Nil)
+ }
+ implicit def liftTuple17[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5], liftT6: Liftable[T6], liftT7: Liftable[T7], liftT8: Liftable[T8], liftT9: Liftable[T9], liftT10: Liftable[T10], liftT11: Liftable[T11], liftT12: Liftable[T12], liftT13: Liftable[T13], liftT14: Liftable[T14], liftT15: Liftable[T15], liftT16: Liftable[T16], liftT17: Liftable[T17]): Liftable[Tuple17[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: liftT7(t._7) :: liftT8(t._8) :: liftT9(t._9) :: liftT10(t._10) :: liftT11(t._11) :: liftT12(t._12) :: liftT13(t._13) :: liftT14(t._14) :: liftT15(t._15) :: liftT16(t._16) :: liftT17(t._17) :: Nil)
+ }
+ implicit def liftTuple18[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5], liftT6: Liftable[T6], liftT7: Liftable[T7], liftT8: Liftable[T8], liftT9: Liftable[T9], liftT10: Liftable[T10], liftT11: Liftable[T11], liftT12: Liftable[T12], liftT13: Liftable[T13], liftT14: Liftable[T14], liftT15: Liftable[T15], liftT16: Liftable[T16], liftT17: Liftable[T17], liftT18: Liftable[T18]): Liftable[Tuple18[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: liftT7(t._7) :: liftT8(t._8) :: liftT9(t._9) :: liftT10(t._10) :: liftT11(t._11) :: liftT12(t._12) :: liftT13(t._13) :: liftT14(t._14) :: liftT15(t._15) :: liftT16(t._16) :: liftT17(t._17) :: liftT18(t._18) :: Nil)
+ }
+ implicit def liftTuple19[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5], liftT6: Liftable[T6], liftT7: Liftable[T7], liftT8: Liftable[T8], liftT9: Liftable[T9], liftT10: Liftable[T10], liftT11: Liftable[T11], liftT12: Liftable[T12], liftT13: Liftable[T13], liftT14: Liftable[T14], liftT15: Liftable[T15], liftT16: Liftable[T16], liftT17: Liftable[T17], liftT18: Liftable[T18], liftT19: Liftable[T19]): Liftable[Tuple19[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: liftT7(t._7) :: liftT8(t._8) :: liftT9(t._9) :: liftT10(t._10) :: liftT11(t._11) :: liftT12(t._12) :: liftT13(t._13) :: liftT14(t._14) :: liftT15(t._15) :: liftT16(t._16) :: liftT17(t._17) :: liftT18(t._18) :: liftT19(t._19) :: Nil)
+ }
+ implicit def liftTuple20[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5], liftT6: Liftable[T6], liftT7: Liftable[T7], liftT8: Liftable[T8], liftT9: Liftable[T9], liftT10: Liftable[T10], liftT11: Liftable[T11], liftT12: Liftable[T12], liftT13: Liftable[T13], liftT14: Liftable[T14], liftT15: Liftable[T15], liftT16: Liftable[T16], liftT17: Liftable[T17], liftT18: Liftable[T18], liftT19: Liftable[T19], liftT20: Liftable[T20]): Liftable[Tuple20[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: liftT7(t._7) :: liftT8(t._8) :: liftT9(t._9) :: liftT10(t._10) :: liftT11(t._11) :: liftT12(t._12) :: liftT13(t._13) :: liftT14(t._14) :: liftT15(t._15) :: liftT16(t._16) :: liftT17(t._17) :: liftT18(t._18) :: liftT19(t._19) :: liftT20(t._20) :: Nil)
+ }
+ implicit def liftTuple21[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5], liftT6: Liftable[T6], liftT7: Liftable[T7], liftT8: Liftable[T8], liftT9: Liftable[T9], liftT10: Liftable[T10], liftT11: Liftable[T11], liftT12: Liftable[T12], liftT13: Liftable[T13], liftT14: Liftable[T14], liftT15: Liftable[T15], liftT16: Liftable[T16], liftT17: Liftable[T17], liftT18: Liftable[T18], liftT19: Liftable[T19], liftT20: Liftable[T20], liftT21: Liftable[T21]): Liftable[Tuple21[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: liftT7(t._7) :: liftT8(t._8) :: liftT9(t._9) :: liftT10(t._10) :: liftT11(t._11) :: liftT12(t._12) :: liftT13(t._13) :: liftT14(t._14) :: liftT15(t._15) :: liftT16(t._16) :: liftT17(t._17) :: liftT18(t._18) :: liftT19(t._19) :: liftT20(t._20) :: liftT21(t._21) :: Nil)
+ }
+ implicit def liftTuple22[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22](implicit liftT1: Liftable[T1], liftT2: Liftable[T2], liftT3: Liftable[T3], liftT4: Liftable[T4], liftT5: Liftable[T5], liftT6: Liftable[T6], liftT7: Liftable[T7], liftT8: Liftable[T8], liftT9: Liftable[T9], liftT10: Liftable[T10], liftT11: Liftable[T11], liftT12: Liftable[T12], liftT13: Liftable[T13], liftT14: Liftable[T14], liftT15: Liftable[T15], liftT16: Liftable[T16], liftT17: Liftable[T17], liftT18: Liftable[T18], liftT19: Liftable[T19], liftT20: Liftable[T20], liftT21: Liftable[T21], liftT22: Liftable[T22]): Liftable[Tuple22[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22]] = Liftable { t =>
+ SyntacticTuple(liftT1(t._1) :: liftT2(t._2) :: liftT3(t._3) :: liftT4(t._4) :: liftT5(t._5) :: liftT6(t._6) :: liftT7(t._7) :: liftT8(t._8) :: liftT9(t._9) :: liftT10(t._10) :: liftT11(t._11) :: liftT12(t._12) :: liftT13(t._13) :: liftT14(t._14) :: liftT15(t._15) :: liftT16(t._16) :: liftT17(t._17) :: liftT18(t._18) :: liftT19(t._19) :: liftT20(t._20) :: liftT21(t._21) :: liftT22(t._22) :: Nil)
+ }
+ }
+
+ trait StandardUnliftableInstances {
+ private def unliftPrimitive[Unboxed: ClassTag, Boxed: ClassTag] = Unliftable[Unboxed] {
+ case Literal(Constant(value))
+ if value.getClass == implicitly[ClassTag[Boxed]].runtimeClass
+ || value.getClass == implicitly[ClassTag[Unboxed]].runtimeClass =>
+ value.asInstanceOf[Unboxed]
+ }
+ implicit def unliftByte: Unliftable[Byte] = unliftPrimitive[Byte, java.lang.Byte]
+ implicit def unliftShort: Unliftable[Short] = unliftPrimitive[Short, java.lang.Short]
+ implicit def unliftChar: Unliftable[Char] = unliftPrimitive[Char, java.lang.Character]
+ implicit def unliftInt: Unliftable[Int] = unliftPrimitive[Int, java.lang.Integer]
+ implicit def unliftLong: Unliftable[Long] = unliftPrimitive[Long, java.lang.Long]
+ implicit def unliftFloat: Unliftable[Float] = unliftPrimitive[Float, java.lang.Float]
+ implicit def unliftDouble: Unliftable[Double] = unliftPrimitive[Double, java.lang.Double]
+ implicit def unliftBoolean: Unliftable[Boolean] = unliftPrimitive[Boolean, java.lang.Boolean]
+ implicit def unliftUnit: Unliftable[Unit] = unliftPrimitive[Unit, scala.runtime.BoxedUnit]
+ implicit def unliftString: Unliftable[String] = Unliftable { case Literal(Constant(s: String)) => s }
+
+ implicit def unliftScalaSymbol: Unliftable[scala.Symbol] = Unliftable {
+ case Apply(ScalaDot(stdnme.Symbol), List(Literal(Constant(name: String)))) => scala.Symbol(name)
+ }
+
+ implicit def unliftName[T <: Name : ClassTag]: Unliftable[T] = Unliftable[T] { case Ident(name: T) => name; case Bind(name: T, Ident(stdnme.WILDCARD)) => name }
+ implicit def unliftType: Unliftable[Type] = Unliftable[Type] { case tt: TypeTree if tt.tpe != null => tt.tpe }
+ implicit def unliftConstant: Unliftable[Constant] = Unliftable[Constant] { case Literal(const) => const }
+
+ implicit def unliftTuple2[T1, T2](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2]): Unliftable[Tuple2[T1, T2]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: Nil) => Tuple2(v1, v2)
+ }
+ implicit def unliftTuple3[T1, T2, T3](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3]): Unliftable[Tuple3[T1, T2, T3]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: Nil) => Tuple3(v1, v2, v3)
+ }
+ implicit def unliftTuple4[T1, T2, T3, T4](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4]): Unliftable[Tuple4[T1, T2, T3, T4]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: Nil) => Tuple4(v1, v2, v3, v4)
+ }
+ implicit def unliftTuple5[T1, T2, T3, T4, T5](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5]): Unliftable[Tuple5[T1, T2, T3, T4, T5]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: Nil) => Tuple5(v1, v2, v3, v4, v5)
+ }
+ implicit def unliftTuple6[T1, T2, T3, T4, T5, T6](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6]): Unliftable[Tuple6[T1, T2, T3, T4, T5, T6]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: Nil) => Tuple6(v1, v2, v3, v4, v5, v6)
+ }
+ implicit def unliftTuple7[T1, T2, T3, T4, T5, T6, T7](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7]): Unliftable[Tuple7[T1, T2, T3, T4, T5, T6, T7]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: Nil) => Tuple7(v1, v2, v3, v4, v5, v6, v7)
+ }
+ implicit def unliftTuple8[T1, T2, T3, T4, T5, T6, T7, T8](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8]): Unliftable[Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: Nil) => Tuple8(v1, v2, v3, v4, v5, v6, v7, v8)
+ }
+ implicit def unliftTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9]): Unliftable[Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: Nil) => Tuple9(v1, v2, v3, v4, v5, v6, v7, v8, v9)
+ }
+ implicit def unliftTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10]): Unliftable[Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: Nil) => Tuple10(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)
+ }
+ implicit def unliftTuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11]): Unliftable[Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: Nil) => Tuple11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)
+ }
+ implicit def unliftTuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12]): Unliftable[Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: Nil) => Tuple12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)
+ }
+ implicit def unliftTuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13]): Unliftable[Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: Nil) => Tuple13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)
+ }
+ implicit def unliftTuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14]): Unliftable[Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: Nil) => Tuple14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)
+ }
+ implicit def unliftTuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14], UnliftT15: Unliftable[T15]): Unliftable[Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: UnliftT15(v15) :: Nil) => Tuple15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)
+ }
+ implicit def unliftTuple16[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14], UnliftT15: Unliftable[T15], UnliftT16: Unliftable[T16]): Unliftable[Tuple16[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: UnliftT15(v15) :: UnliftT16(v16) :: Nil) => Tuple16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)
+ }
+ implicit def unliftTuple17[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14], UnliftT15: Unliftable[T15], UnliftT16: Unliftable[T16], UnliftT17: Unliftable[T17]): Unliftable[Tuple17[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: UnliftT15(v15) :: UnliftT16(v16) :: UnliftT17(v17) :: Nil) => Tuple17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17)
+ }
+ implicit def unliftTuple18[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14], UnliftT15: Unliftable[T15], UnliftT16: Unliftable[T16], UnliftT17: Unliftable[T17], UnliftT18: Unliftable[T18]): Unliftable[Tuple18[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: UnliftT15(v15) :: UnliftT16(v16) :: UnliftT17(v17) :: UnliftT18(v18) :: Nil) => Tuple18(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18)
+ }
+ implicit def unliftTuple19[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14], UnliftT15: Unliftable[T15], UnliftT16: Unliftable[T16], UnliftT17: Unliftable[T17], UnliftT18: Unliftable[T18], UnliftT19: Unliftable[T19]): Unliftable[Tuple19[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: UnliftT15(v15) :: UnliftT16(v16) :: UnliftT17(v17) :: UnliftT18(v18) :: UnliftT19(v19) :: Nil) => Tuple19(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19)
+ }
+ implicit def unliftTuple20[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14], UnliftT15: Unliftable[T15], UnliftT16: Unliftable[T16], UnliftT17: Unliftable[T17], UnliftT18: Unliftable[T18], UnliftT19: Unliftable[T19], UnliftT20: Unliftable[T20]): Unliftable[Tuple20[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: UnliftT15(v15) :: UnliftT16(v16) :: UnliftT17(v17) :: UnliftT18(v18) :: UnliftT19(v19) :: UnliftT20(v20) :: Nil) => Tuple20(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20)
+ }
+ implicit def unliftTuple21[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14], UnliftT15: Unliftable[T15], UnliftT16: Unliftable[T16], UnliftT17: Unliftable[T17], UnliftT18: Unliftable[T18], UnliftT19: Unliftable[T19], UnliftT20: Unliftable[T20], UnliftT21: Unliftable[T21]): Unliftable[Tuple21[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: UnliftT15(v15) :: UnliftT16(v16) :: UnliftT17(v17) :: UnliftT18(v18) :: UnliftT19(v19) :: UnliftT20(v20) :: UnliftT21(v21) :: Nil) => Tuple21(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21)
+ }
+ implicit def unliftTuple22[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22](implicit UnliftT1: Unliftable[T1], UnliftT2: Unliftable[T2], UnliftT3: Unliftable[T3], UnliftT4: Unliftable[T4], UnliftT5: Unliftable[T5], UnliftT6: Unliftable[T6], UnliftT7: Unliftable[T7], UnliftT8: Unliftable[T8], UnliftT9: Unliftable[T9], UnliftT10: Unliftable[T10], UnliftT11: Unliftable[T11], UnliftT12: Unliftable[T12], UnliftT13: Unliftable[T13], UnliftT14: Unliftable[T14], UnliftT15: Unliftable[T15], UnliftT16: Unliftable[T16], UnliftT17: Unliftable[T17], UnliftT18: Unliftable[T18], UnliftT19: Unliftable[T19], UnliftT20: Unliftable[T20], UnliftT21: Unliftable[T21], UnliftT22: Unliftable[T22]): Unliftable[Tuple22[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22]] = Unliftable {
+ case SyntacticTuple(UnliftT1(v1) :: UnliftT2(v2) :: UnliftT3(v3) :: UnliftT4(v4) :: UnliftT5(v5) :: UnliftT6(v6) :: UnliftT7(v7) :: UnliftT8(v8) :: UnliftT9(v9) :: UnliftT10(v10) :: UnliftT11(v11) :: UnliftT12(v12) :: UnliftT13(v13) :: UnliftT14(v14) :: UnliftT15(v15) :: UnliftT16(v16) :: UnliftT17(v17) :: UnliftT18(v18) :: UnliftT19(v19) :: UnliftT20(v20) :: UnliftT21(v21) :: UnliftT22(v22) :: Nil) => Tuple22(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22)
+ }
+ }
+
+ // names used internally by implementations of standard liftables and unliftables
+ // can't be `private object nme` because of https://groups.google.com/forum/#!topic/scala-internals/b-Full9WZeE
+ // can't be `private[this] object nme` because then STARR has problems prioritizing this.nme over self.nme
+ // therefore I'm essentially forced to give this object a non-standard name
+ private object stdnme {
+ val Array = TermName("Array")
+ val collection = TermName("collection")
+ val immutable = TermName("immutable")
+ val Left = TermName("Left")
+ val List = TermName("List")
+ val Map = TermName("Map")
+ val None = TermName("None")
+ val Nil = TermName("Nil")
+ val Right = TermName("Right")
+ val Set = TermName("Set")
+ val Some = TermName("Some")
+ val Symbol = TermName("Symbol")
+ val util = TermName("util")
+ val Vector = TermName("Vector")
+ val WILDCARD = self.nme.WILDCARD
+ }
+}
diff --git a/src/reflect/scala/reflect/api/StandardNames.scala b/src/reflect/scala/reflect/api/StandardNames.scala
index 4886e4f8f7..19bdfcae59 100644
--- a/src/reflect/scala/reflect/api/StandardNames.scala
+++ b/src/reflect/scala/reflect/api/StandardNames.scala
@@ -2,7 +2,8 @@
* Copyright 2005-2013 LAMP/EPFL
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package api
// Q: I have a pretty name. Can I put it here?
@@ -27,15 +28,23 @@ package api
trait StandardNames {
self: Universe =>
+ /** @see [[termNames]] */
+ @deprecated("Use `termNames` instead", "2.11.0")
+ val nme: TermNamesApi
+
/** A value containing all [[TermNamesApi standard term names]].
* @group StandardNames
*/
- val nme: TermNamesApi
+ val termNames: TermNamesApi
+
+ /** @see [[typeNames]] */
+ @deprecated("Use `typeNames` instead", "2.11.0")
+ val tpnme: TypeNamesApi
/** A value containing all [[TypeNamesApi standard type names]].
* @group StandardNames
*/
- val tpnme: TypeNamesApi
+ val typeNames: TypeNamesApi
/** Defines standard names, common for term and type names: These can be accessed via the [[nme]] and [[tpnme]] members.
* @group API
@@ -84,6 +93,11 @@ trait StandardNames {
*/
val ROOTPKG: NameType
+ /** The term name `<empty>`.
+ * Represents the empty package.
+ */
+ val EMPTY_PACKAGE_NAME: NameType
+
/** The string " " (a single whitespace).
* `LOCAL_SUFFIX_STRING` is appended to the names of local identifiers,
* when it's necessary to prevent a naming conflict. For example, underlying fields
diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala
index c8e03f1d91..dddd3c0e61 100644
--- a/src/reflect/scala/reflect/api/Symbols.scala
+++ b/src/reflect/scala/reflect/api/Symbols.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package api
/**
@@ -29,7 +30,7 @@ package api
* scala> val test = typeOf[C[Int]].member(newTermName("test")).asMethod
* test: reflect.runtime.universe.MethodSymbol = method test
*
- * scala> test.typeSignature
+ * scala> test.info
* res0: reflect.runtime.universe.Type = [U](x: T)(y: U)scala.Int
* }}}
*
@@ -59,99 +60,39 @@ trait Symbols { self: Universe =>
* @group Symbols
* @template
*/
- type Symbol >: Null <: SymbolApi
-
- /** A tag that preserves the identity of the `Symbol` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val SymbolTag: ClassTag[Symbol]
+ type Symbol >: Null <: AnyRef with SymbolApi
/** The type of type symbols representing type, class, and trait declarations,
* as well as type parameters.
* @group Symbols
* @template
*/
- type TypeSymbol >: Null <: Symbol with TypeSymbolApi
-
- /** A tag that preserves the identity of the `TypeSymbol` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val TypeSymbolTag: ClassTag[TypeSymbol]
+ type TypeSymbol >: Null <: TypeSymbolApi with Symbol
/** The type of term symbols representing val, var, def, and object declarations as
* well as packages and value parameters.
* @group Symbols
* @template
*/
- type TermSymbol >: Null <: Symbol with TermSymbolApi
-
- /** A tag that preserves the identity of the `TermSymbol` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val TermSymbolTag: ClassTag[TermSymbol]
+ type TermSymbol >: Null <: TermSymbolApi with Symbol
/** The type of method symbols representing def declarations.
* @group Symbols
* @template
*/
- type MethodSymbol >: Null <: TermSymbol with MethodSymbolApi
-
- /** A tag that preserves the identity of the `MethodSymbol` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val MethodSymbolTag: ClassTag[MethodSymbol]
+ type MethodSymbol >: Null <: MethodSymbolApi with TermSymbol
/** The type of module symbols representing object declarations.
* @group Symbols
* @template
*/
- type ModuleSymbol >: Null <: TermSymbol with ModuleSymbolApi
-
- /** A tag that preserves the identity of the `ModuleSymbol` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ModuleSymbolTag: ClassTag[ModuleSymbol]
+ type ModuleSymbol >: Null <: ModuleSymbolApi with TermSymbol
/** The type of class symbols representing class and trait definitions.
* @group Symbols
* @template
*/
- type ClassSymbol >: Null <: TypeSymbol with ClassSymbolApi
-
- /** A tag that preserves the identity of the `ClassSymbol` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ClassSymbolTag: ClassTag[ClassSymbol]
-
- /** The type of free terms introduced by reification.
- * @group Symbols
- * @template
- */
- type FreeTermSymbol >: Null <: TermSymbol with FreeTermSymbolApi
-
- /** A tag that preserves the identity of the `FreeTermSymbol` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val FreeTermSymbolTag: ClassTag[FreeTermSymbol]
-
- /** The type of free types introduced by reification.
- * @group Symbols
- * @template
- */
- type FreeTypeSymbol >: Null <: TypeSymbol with FreeTypeSymbolApi
-
- /** A tag that preserves the identity of the `FreeTypeSymbol` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val FreeTypeSymbolTag: ClassTag[FreeTypeSymbol]
+ type ClassSymbol >: Null <: ClassSymbolApi with TypeSymbol
/** A special "missing" symbol. Commonly used in the API to denote a default or empty value.
* @group Symbols
@@ -178,12 +119,8 @@ trait Symbols { self: Universe =>
* @groupdesc Helpers These methods enable collections-like operations on symbols.
* @groupname Type TypeSymbol Members
* @groupprio Type -1
- * @groupname FreeType FreeType Symbol Members
- * @groupprio FreeType -2
* @groupname Term TermSymbol Members
* @groupprio Term -1
- * @groupname FreeTerm FreeTerm Symbol Members
- * @groupprio FreeTerm -2
* @groupname Class Class Symbol Members
* @groupprio Class -2
* @groupname Method Method Symbol Members
@@ -218,7 +155,7 @@ trait Symbols { self: Universe =>
/** The name of the symbol as a member of the `Name` type.
* @group Basics
*/
- def name: Name
+ def name: NameType
/** The encoded full path name of this symbol, where outer names and inner names
* are separated by periods.
@@ -226,6 +163,9 @@ trait Symbols { self: Universe =>
*/
def fullName: String
+ /** Position of the tree. */
+ def pos: Position
+
/** Does this symbol represent the definition of a type?
* Note that every symbol is either a term or a type.
* So for every symbol `sym` (except for `NoSymbol`),
@@ -245,7 +185,7 @@ trait Symbols { self: Universe =>
/** Does this symbol represent the definition of a term?
* Note that every symbol is either a term or a type.
* So for every symbol `sym` (except for `NoSymbol`),
- * either `sym.isTerm` is true or `sym.isTerm` is true.
+ * either `sym.isTerm` is true or `sym.isType` is true.
*
* @group Tests
*/
@@ -265,6 +205,15 @@ trait Symbols { self: Universe =>
*/
def isMethod: Boolean = false
+ /** Does this method represent a constructor?
+ *
+ * If `owner` is a class, then this is a vanilla JVM constructor.
+ * If `owner` is a trait, then this is a mixin constructor.
+ *
+ * @group Method
+ */
+ def isConstructor: Boolean
+
/** This symbol cast to a MethodSymbol.
* @throws ScalaReflectionException if `isMethod` is false.
*
@@ -322,45 +271,6 @@ trait Symbols { self: Universe =>
*/
def asClass: ClassSymbol = throw new ScalaReflectionException(s"$this is not a class")
- /** Does this symbol represent a free term captured by reification?
- * If yes, `isTerm` is also guaranteed to be true.
- *
- * @group Tests
- */
- def isFreeTerm: Boolean = false
-
- /** This symbol cast to a free term symbol.
- * @throws ScalaReflectionException if `isFreeTerm` is false.
- *
- * @group Conversions
- */
- def asFreeTerm: FreeTermSymbol = throw new ScalaReflectionException(s"$this is not a free term")
-
- /** Does this symbol represent a free type captured by reification?
- * If yes, `isType` is also guaranteed to be true.
- *
- * @group Tests
- */
- def isFreeType: Boolean = false
-
- /** This symbol cast to a free type symbol.
- * @throws ScalaReflectionException if `isFreeType` is false.
- *
- * @group Conversions
- */
- def asFreeType: FreeTypeSymbol = throw new ScalaReflectionException(s"$this is not a free type")
-
- /** @group Constructors */
- def newTermSymbol(name: TermName, pos: Position = NoPosition, flags: FlagSet = NoFlags): TermSymbol
- /** @group Constructors */
- def newModuleAndClassSymbol(name: Name, pos: Position = NoPosition, flags: FlagSet = NoFlags): (ModuleSymbol, ClassSymbol)
- /** @group Constructors */
- def newMethodSymbol(name: TermName, pos: Position = NoPosition, flags: FlagSet = NoFlags): MethodSymbol
- /** @group Constructors */
- def newTypeSymbol(name: TypeName, pos: Position = NoPosition, flags: FlagSet = NoFlags): TypeSymbol
- /** @group Constructors */
- def newClassSymbol(name: TypeName, pos: Position = NoPosition, flags: FlagSet = NoFlags): ClassSymbol
-
/** Source file if this symbol is created during this compilation run,
* or a class file if this symbol is loaded from a *.class or *.jar.
*
@@ -370,6 +280,7 @@ trait Symbols { self: Universe =>
*
* @group Basics
*/
+ @deprecated("Use `pos.source.file` instead", "2.11.0")
def associatedFile: scala.reflect.io.AbstractFile
/** A list of annotations attached to this Symbol.
@@ -382,15 +293,32 @@ trait Symbols { self: Universe =>
* For a module: the class with the same name in the same package.
* For all others: NoSymbol
*
+ * This API may return unexpected results for module classes, packages and package classes.
+ * Use `companion` instead in order to get predictable results.
+ *
* @group Basics
*/
+ @deprecated("Use `companion` instead, but beware of possible changes in behavior", "2.11.0")
def companionSymbol: Symbol
+ /** For a class: its companion object if exists.
+ * For a module or a module class: companion class of the module if exists.
+ * For a package or a package class: NoSymbol.
+ * For all others: NoSymbol.
+ */
+ def companion: Symbol
+
+ /** @see [[infoIn]] */
+ def typeSignatureIn(site: Type): Type
+
/** The type signature of this symbol seen as a member of given type `site`.
*
* @group Basics
*/
- def typeSignatureIn(site: Type): Type
+ def infoIn(site: Type): Type
+
+ /** @see [[info]] */
+ def typeSignature: Type
/** The type signature of this symbol.
*
@@ -398,17 +326,27 @@ trait Symbols { self: Universe =>
* instantiation of a generic type. For example, signature
* of the method `def map[B](f: (A) ⇒ B): List[B]`, which refers to the type parameter `A` of the declaring class `List[A]`,
* will always feature `A`, regardless of whether `map` is loaded from the `List[_]` or from `List[Int]`. To get a signature
- * with type parameters appropriately instantiated, one should use `typeSignatureIn`.
+ * with type parameters appropriately instantiated, one should use `infoIn`.
*
* @group Basics
*/
- def typeSignature: Type
+ def info: Type
+
+ /** @see [[overrides]] */
+ @deprecated("Use `overrides` instead", "2.11.0")
+ def allOverriddenSymbols: List[Symbol]
/** Returns all symbols overriden by this symbol.
*
* @group Basics
*/
- def allOverriddenSymbols: List[Symbol]
+ def overrides: List[Symbol]
+
+ /** The overloaded alternatives of this symbol
+ *
+ * @group Basics
+ */
+ def alternatives: List[Symbol]
/******************* tests *******************/
@@ -427,16 +365,13 @@ trait Symbols { self: Universe =>
*/
def isImplementationArtifact: Boolean
- /** Does this symbol represent a local declaration or definition?
- *
- * If yes, either `isPrivate` or `isProtected` are guaranteed to be true.
- * Local symbols can only be accessed from the same object instance.
- *
- * If yes, `privateWithin` might tell more about this symbol's visibility scope.
+ /** Does this symbol represent a declaration or definition written in a source file as `private[this]`
+ * or generated in tree/symbol form with the combination of flags LOCAL and PRIVATE?
+ * If yes, `isPrivate` is guaranteed to be true,
*
* @group Tests
*/
- def isLocal: Boolean
+ def isPrivateThis: Boolean
/** Does this symbol represent a private declaration or definition?
* If yes, `privateWithin` might tell more about this symbol's visibility scope.
@@ -445,6 +380,14 @@ trait Symbols { self: Universe =>
*/
def isPrivate: Boolean
+ /** Does this symbol represent a declaration or definition written in a source file as `protected[this]`
+ * or generated in tree/symbol form with the combination of flags LOCAL and PROTECTED?
+ * If yes, `isProtected` is guaranteed to be true,
+ *
+ * @group Tests
+ */
+ def isProtectedThis: Boolean
+
/** Does this symbol represent a protected declaration or definition?
* If yes, `privateWithin` might tell more about this symbol's visibility scope.
*
@@ -459,7 +402,7 @@ trait Symbols { self: Universe =>
def isPublic: Boolean
/**
- * Set when symbol has a modifier of the form private[X], NoSymbol otherwise.
+ * Set when symbol has a modifier of the form private[X] or protected[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])
@@ -488,7 +431,7 @@ trait Symbols { self: Universe =>
def privateWithin: Symbol
/** Does this symbol represent the definition of a package?
- * If yes, `isTerm` is also guaranteed to be true.
+ * Known issues: [[https://issues.scala-lang.org/browse/SI-6732]].
*
* @group Tests
*/
@@ -501,12 +444,6 @@ trait Symbols { self: Universe =>
*/
def isPackageClass: Boolean
- /** Does this symbol or its underlying type represent a typechecking error?
- *
- * @group Tests
- */
- def isErroneous : 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.
@@ -522,11 +459,11 @@ trait Symbols { self: Universe =>
*/
def isFinal: Boolean
- /** Is this symbol overriding something?
+ /** Is this symbol abstract (i.e. an abstract class, an abstract method, value or type member)?
*
* @group Tests
*/
- def isOverride: Boolean
+ def isAbstract: Boolean
/** Is this symbol labelled as "abstract override"?
*
@@ -660,12 +597,6 @@ trait Symbols { self: Universe =>
*/
def isLazy: Boolean
- /** The overloaded alternatives of this symbol
- *
- * @group Term
- */
- def alternatives: List[Symbol]
-
/** Used to provide a better error message for `asMethod` */
override protected def isOverloadedMethod = alternatives exists (_.isMethod)
@@ -751,7 +682,7 @@ trait Symbols { self: Universe =>
* Example: Given a class declaration `class C[T] { ... } `, that generates a symbol
* `C`. Then `C.toType` is the type `C[T]`.
*
- * By contrast, `C.typeSignature` would be a type signature of form
+ * By contrast, `C.info` would be a type signature of form
* `PolyType(ClassInfoType(...))` that describes type parameters, value
* parameters, parent types, and members of `C`.
*
@@ -774,13 +705,6 @@ trait Symbols { self: Universe =>
*/
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.
- *
- * @group Type
- */
- def isSkolem : Boolean
-
/** Does this symbol represent the definition of a type alias?
*
* @group Type
@@ -791,6 +715,7 @@ trait Symbols { self: Universe =>
*
* @group Type
*/
+ @deprecated("Use isAbstract instead", "2.11.0")
def isAbstractType : Boolean
/** Does this symbol represent an existentially bound type?
@@ -816,15 +741,6 @@ trait Symbols { self: Universe =>
final override def isMethod = true
final override def asMethod = this
- /** Does this method represent a constructor?
- *
- * If `owner` is a class, then this is a vanilla JVM constructor.
- * If `owner` is a trait, then this is a mixin constructor.
- *
- * @group Method
- */
- def isConstructor: Boolean
-
/** Does this symbol denote the primary constructor of its enclosing class?
*
* @group Method
@@ -837,6 +753,10 @@ trait Symbols { self: Universe =>
*/
def typeParams: List[Symbol]
+ /** @see [[paramLists]] */
+ @deprecated("Use `paramLists` instead", "2.11.0")
+ def paramss: List[List[Symbol]]
+
/** All parameter lists of the method.
* The name ending with "ss" indicates that the result type is a list of lists.
*
@@ -846,7 +766,7 @@ trait Symbols { self: Universe =>
*
* @group Method
*/
- def paramss: List[List[Symbol]]
+ def paramLists: List[List[Symbol]]
/** Does this method support variable length argument lists?
*
@@ -859,6 +779,14 @@ trait Symbols { self: Universe =>
* @group Method
*/
def returnType: Type
+
+ /** Exceptions that this method is known to throw.
+ * For Scala methods, the list is calculated from [[throws]] annotations present on a method.
+ * For Java methods, the list is calculated from `throws` clauses attached to the method and stored in bytecode.
+ *
+ * @group Method
+ */
+ def exceptions: List[Symbol]
}
/** The API of module symbols.
@@ -924,6 +852,7 @@ trait Symbols { self: Universe =>
*
* @group Class
*/
+ @deprecated("Use isAbstract instead", "2.11.0")
def isAbstractClass: Boolean
/** Does this symbol represent a case class?
@@ -973,50 +902,37 @@ trait Symbols { self: Universe =>
*/
def thisPrefix: Type
- /** For a polymorphic class/trait, its type parameters, the empty list for all other classes/trait
+ /** The type `C.super[M]`, where `C` is the current class and `M` is supertpe.
*
* @group Class
*/
- def typeParams: List[Symbol]
- }
+ def superPrefix(supertpe: Type): Type
- /** The API of free term symbols.
- * The main source of information about symbols is the [[Symbols]] page.
- *
- * $SYMACCESSORS
- * @group API
- */
- trait FreeTermSymbolApi extends TermSymbolApi { this: FreeTermSymbol =>
- final override def isFreeTerm = true
- final override def asFreeTerm = this
-
- /** The place where this symbol has been spawned
+ /** For a polymorphic class/trait, its type parameters, the empty list for all other classes/trait
*
- * @group FreeTerm
+ * @group Class
*/
- def origin: String
+ def typeParams: List[Symbol]
- /** The valus this symbol refers to
+ /** For a Scala class or module class, the primary constructor of the class.
+ * For a Scala trait, its mixin constructor.
+ * For a Scala package class, NoSymbol.
+ * For a Java class, NoSymbol.
*
- * @group FreeTerm
- */
- def value: Any
- }
-
- /** The API of free type symbols.
- * The main source of information about symbols is the [[Symbols]] page.
- *
- * $SYMACCESSORS
- * @group API
- */
- trait FreeTypeSymbolApi extends TypeSymbolApi { this: FreeTypeSymbol =>
- final override def isFreeType = true
- final override def asFreeType = this
-
- /** The place where this symbol has been spawned
+ * Known issues: Due to SI-8367, primaryConstructor may return unexpected results
+ * when called for Java classes (for some vague definition of a "Java class", which apparently
+ * not only includes javac-produced classfiles, but also consists of classes defined in
+ * Scala programs under the java.lang package). What's even worse, for some Java classes
+ * we can't even guarantee stability of the return value - depending on your classloader configuration
+ * and/or JDK version you might get different primaryConstructor for the same ClassSymbol.
+ * We have logged these issues at SI-8193.
*
- * @group FreeType
+ * @group Class
*/
- def origin: String
+ // TODO: SI-8193 I think we should only return a non-empty symbol if called for Scala classes
+ // returning something for traits and module classes is outright confusing
+ // This, however, will require some refactoring in the compiler, so I'll leave it for later
+ // as at the moment we don't have time or risk tolerance for that
+ def primaryConstructor: Symbol
}
}
diff --git a/src/reflect/scala/reflect/api/TagInterop.scala b/src/reflect/scala/reflect/api/TagInterop.scala
deleted file mode 100644
index 5de811578e..0000000000
--- a/src/reflect/scala/reflect/api/TagInterop.scala
+++ /dev/null
@@ -1,43 +0,0 @@
-package scala.reflect
-package api
-
-/**
- * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
- *
- * This trait provides type tag <-> manifest interoperability.
- * @group ReflectionAPI
- *
- * @groupname TagInterop TypeTag and Manifest Interoperability
- */
-trait TagInterop { self: Universe =>
- // TODO `mirror` parameters are now of type `Any`, because I can't make these path-dependent types work
- // if you're brave enough, replace `Any` with `Mirror`, recompile and run interop_typetags_are_manifests.scala
-
- /**
- * Convert a [[scala.reflect.api.TypeTags#TypeTag]] to a [[scala.reflect.Manifest]].
- *
- * Compiler usually generates these conversions automatically, when a type tag for a type `T` is in scope,
- * and an implicit of type `Manifest[T]` is requested, but this method can also be called manually.
- * For example:
- * {{{
- * typeTagToManifest(scala.reflect.runtime.currentMirror, implicitly[TypeTag[String]])
- * }}}
- * @group TagInterop
- */
- def typeTagToManifest[T: ClassTag](mirror: Any, tag: Universe#TypeTag[T]): Manifest[T] =
- throw new UnsupportedOperationException("This universe does not support tag -> manifest conversions. Use a JavaUniverse, e.g. the scala.reflect.runtime.universe.")
-
- /**
- * Convert a [[scala.reflect.Manifest]] to a [[scala.reflect.api.TypeTags#TypeTag]].
- *
- * Compiler usually generates these conversions automatically, when a manifest for a type `T` is in scope,
- * and an implicit of type `TypeTag[T]` is requested, but this method can also be called manually.
- * For example:
- * {{{
- * manifestToTypeTag(scala.reflect.runtime.currentMirror, implicitly[Manifest[String]])
- * }}}
- * @group TagInterop
- */
- def manifestToTypeTag[T](mirror: Any, manifest: Manifest[T]): Universe#TypeTag[T] =
- throw new UnsupportedOperationException("This universe does not support manifest -> tag conversions. Use a JavaUniverse, e.g. the scala.reflect.runtime.universe.")
-}
diff --git a/src/reflect/scala/reflect/api/TreeCreator.scala b/src/reflect/scala/reflect/api/TreeCreator.scala
index 6969418470..027c840955 100644
--- a/src/reflect/scala/reflect/api/TreeCreator.scala
+++ b/src/reflect/scala/reflect/api/TreeCreator.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package api
/** This is an internal implementation class.
diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala
index 0937a93738..ff8926651b 100644
--- a/src/reflect/scala/reflect/api/Trees.scala
+++ b/src/reflect/scala/reflect/api/Trees.scala
@@ -2,7 +2,8 @@
* Copyright 2005-2013 LAMP/EPFL
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package api
/**
@@ -58,13 +59,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Tree >: Null <: TreeApi
-
- /** A tag that preserves the identity of the `Tree` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val TreeTag: ClassTag[Tree]
+ type Tree >: Null <: AnyRef with TreeApi
/** The API that all trees support.
* The main source of information about trees is the [[scala.reflect.api.Trees]] page.
@@ -75,11 +70,25 @@ trait Trees { self: Universe =>
def isDef: Boolean
/** Is this tree one of the empty trees?
- * Empty trees are: the `EmptyTree` null object, `TypeTree` instances that don't carry a type
- * and the special `emptyValDef` singleton.
+ *
+ * Empty trees are: the `EmptyTree` null object and `TypeTree` instances that don't carry a type.
+ *
+ * @see `canHaveAttrs`
*/
def isEmpty: Boolean
+ /** Is this tree not an empty tree?
+ *
+ * @see `isEmpty`
+ */
+ def nonEmpty: Boolean
+
+ /** Can this tree carry attributes (i.e. symbols, types or positions)?
+ * Typically the answer is yes, except for the `EmptyTree` null object and
+ * two special singletons: `noSelfType` and `pendingSuperCall`.
+ */
+ def canHaveAttrs: Boolean
+
/** The canonical way to test if a Tree represents a term.
*/
def isTerm: Boolean
@@ -159,29 +168,6 @@ trait Trees { self: Universe =>
*/
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).
@@ -207,13 +193,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type TermTree >: Null <: AnyRef with Tree with TermTreeApi
-
- /** A tag that preserves the identity of the `TermTree` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val TermTreeTag: ClassTag[TermTree]
+ type TermTree >: Null <: TermTreeApi with Tree
/** The API that all term trees support
* @group API
@@ -226,13 +206,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type TypTree >: Null <: AnyRef with Tree with TypTreeApi
-
- /** A tag that preserves the identity of the `TypTree` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val TypTreeTag: ClassTag[TypTree]
+ type TypTree >: Null <: TypTreeApi with Tree
/** The API that all typ trees support
* @group API
@@ -240,17 +214,14 @@ trait Trees { self: Universe =>
trait TypTreeApi extends TreeApi { this: TypTree =>
}
- /** A tree with a mutable symbol field, initialized to NoSymbol.
+ /** A tree that carries a symbol, e.g. by defining it (`DefTree`) or by referring to it (`RefTree`).
+ * Such trees start their life naked, returning `NoSymbol`, but after being typechecked without errors
+ * they hold non-empty symbols.
+ *
* @group Trees
* @template
*/
- type SymTree >: Null <: AnyRef with Tree with SymTreeApi
-
- /** A tag that preserves the identity of the `SymTree` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val SymTreeTag: ClassTag[SymTree]
+ type SymTree >: Null <: SymTreeApi with Tree
/** The API that all sym trees support
* @group API
@@ -260,24 +231,18 @@ trait Trees { self: Universe =>
def symbol: Symbol
}
- /** A tree with a name - effectively, a DefTree or RefTree.
+ /** A tree that carries a name, e.g. by defining it (`DefTree`) or by referring to it (`RefTree`).
* @group Trees
* @template
*/
- type NameTree >: Null <: AnyRef with Tree with NameTreeApi
-
- /** A tag that preserves the identity of the `NameTree` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val NameTreeTag: ClassTag[NameTree]
+ type NameTree >: Null <: NameTreeApi with Tree
/** The API that all name trees support
* @group API
*/
trait NameTreeApi extends TreeApi { this: NameTree =>
/** The underlying name.
- * For example, the `<List>` part of `Ident("List": TermName)`.
+ * For example, the `List` part of `Ident(TermName("List"))`.
*/
def name: Name
}
@@ -288,20 +253,14 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type RefTree >: Null <: SymTree with NameTree with RefTreeApi
-
- /** A tag that preserves the identity of the `RefTree` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val RefTreeTag: ClassTag[RefTree]
+ type RefTree >: Null <: RefTreeApi with SymTree with NameTree
/** The API that all ref trees support
* @group API
*/
trait RefTreeApi extends SymTreeApi with NameTreeApi { this: RefTree =>
/** The qualifier of the reference.
- * For example, the `<scala>` part of `Select("scala": TermName, "List": TermName)`.
+ * For example, the `Ident(TermName("scala"))` part of `Select(Ident(TermName("scala")), TermName("List"))`.
* `EmptyTree` for `Ident` instances.
*/
def qualifier: Tree
@@ -310,17 +269,28 @@ trait Trees { self: Universe =>
def name: Name
}
- /** A tree which defines a symbol-carrying entity.
- * @group Trees
- * @template
+ /** The constructor/extractor for `RefTree` instances.
+ * @group Extractors
+ */
+ val RefTree: RefTreeExtractor
+
+ /** An extractor class to create and pattern match with syntax `RefTree(qual, name)`.
+ * This AST node corresponds to either Ident, Select or SelectFromTypeTree.
+ * @group Extractors
*/
- type DefTree >: Null <: SymTree with NameTree with DefTreeApi
+ abstract class RefTreeExtractor {
+ def apply(qualifier: Tree, name: Name): RefTree
+ def unapply(refTree: RefTree): Option[(Tree, Name)]
+ }
- /** A tag that preserves the identity of the `DefTree` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
+ /** A tree representing a symbol-defining entity:
+ * 1) A declaration or a definition (type, class, object, package, val, var, or def)
+ * 2) `Bind` that is used to represent binding occurrences in pattern matches
+ * 3) `LabelDef` that is used internally to represent while loops
+ * @group Trees
+ * @template
*/
- implicit val DefTreeTag: ClassTag[DefTree]
+ type DefTree >: Null <: DefTreeApi with SymTree with NameTree
/** The API that all def trees support
* @group API
@@ -335,13 +305,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type MemberDef >: Null <: DefTree with MemberDefApi
-
- /** A tag that preserves the identity of the `MemberDef` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val MemberDefTag: ClassTag[MemberDef]
+ type MemberDef >: Null <: MemberDefApi with DefTree
/** The API that all member defs support
* @group API
@@ -355,13 +319,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type PackageDef >: Null <: MemberDef with PackageDefApi
-
- /** A tag that preserves the identity of the `PackageDef` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val PackageDefTag: ClassTag[PackageDef]
+ type PackageDef >: Null <: PackageDefApi with MemberDef
/** The constructor/extractor for `PackageDef` instances.
* @group Extractors
@@ -394,13 +352,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type ImplDef >: Null <: MemberDef with ImplDefApi
-
- /** A tag that preserves the identity of the `ImplDef` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ImplDefTag: ClassTag[ImplDef]
+ type ImplDef >: Null <: ImplDefApi with MemberDef
/** The API that all impl defs support
* @group API
@@ -414,13 +366,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type ClassDef >: Null <: ImplDef with ClassDefApi
-
- /** A tag that preserves the identity of the `ClassDef` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ClassDefTag: ClassTag[ClassDef]
+ type ClassDef >: Null <: ClassDefApi with ImplDef
/** The constructor/extractor for `ClassDef` instances.
* @group Extractors
@@ -440,6 +386,10 @@ trait Trees { self: Universe =>
abstract class ClassDefExtractor {
def apply(mods: Modifiers, name: TypeName, tparams: List[TypeDef], impl: Template): ClassDef
def unapply(classDef: ClassDef): Option[(Modifiers, TypeName, List[TypeDef], Template)]
+
+ /** @see [[InternalApi.classDef]] */
+ @deprecated("Use `internal.classDef` instead", "2.11.0")
+ def apply(sym: Symbol, impl: Template)(implicit token: CompatToken): ClassDef = internal.classDef(sym, impl)
}
/** The API that all class defs support
@@ -465,13 +415,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type ModuleDef >: Null <: ImplDef with ModuleDefApi
-
- /** A tag that preserves the identity of the `ModuleDef` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ModuleDefTag: ClassTag[ModuleDef]
+ type ModuleDef >: Null <: ModuleDefApi with ImplDef
/** The constructor/extractor for `ModuleDef` instances.
* @group Extractors
@@ -491,6 +435,10 @@ trait Trees { self: Universe =>
abstract class ModuleDefExtractor {
def apply(mods: Modifiers, name: TermName, impl: Template): ModuleDef
def unapply(moduleDef: ModuleDef): Option[(Modifiers, TermName, Template)]
+
+ /** @see [[InternalApi.moduleDef]] */
+ @deprecated("Use `internal.moduleDef` instead", "2.11.0")
+ def apply(sym: Symbol, impl: Template)(implicit token: CompatToken): ModuleDef = internal.moduleDef(sym, impl)
}
/** The API that all module defs support
@@ -511,20 +459,14 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type ValOrDefDef >: Null <: MemberDef with ValOrDefDefApi
-
- /** A tag that preserves the identity of the `ValOrDefDef` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ValOrDefDefTag: ClassTag[ValOrDefDef]
+ type ValOrDefDef >: Null <: ValOrDefDefApi with MemberDef
/** The API that all val defs and def defs support
* @group API
*/
trait ValOrDefDefApi extends MemberDefApi { this: ValOrDefDef =>
/** @inheritdoc */
- def name: Name // can't be a TermName because macros can be type names.
+ def name: TermName
/** The type ascribed to the definition.
* An empty `TypeTree` if the type hasn't been specified explicitly
@@ -548,13 +490,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type ValDef >: Null <: ValOrDefDef with ValDefApi
-
- /** A tag that preserves the identity of the `ValDef` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ValDefTag: ClassTag[ValDef]
+ type ValDef >: Null <: ValDefApi with ValOrDefDef
/** The constructor/extractor for `ValDef` instances.
* @group Extractors
@@ -579,6 +515,14 @@ trait Trees { self: Universe =>
abstract class ValDefExtractor {
def apply(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree): ValDef
def unapply(valDef: ValDef): Option[(Modifiers, TermName, Tree, Tree)]
+
+ /** @see [[InternalApi.valDef]] */
+ @deprecated("Use `internal.valDef` instead", "2.11.0")
+ def apply(sym: Symbol, rhs: Tree)(implicit token: CompatToken): ValDef = internal.valDef(sym, rhs)
+
+ /** @see [[InternalApi.valDef]] */
+ @deprecated("Use `internal.valDef` instead", "2.11.0")
+ def apply(sym: Symbol)(implicit token: CompatToken): ValDef = internal.valDef(sym)
}
/** The API that all val defs support
@@ -603,13 +547,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type DefDef >: Null <: ValOrDefDef with DefDefApi
-
- /** A tag that preserves the identity of the `DefDef` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val DefDefTag: ClassTag[DefDef]
+ type DefDef >: Null <: DefDefApi with ValOrDefDef
/** The constructor/extractor for `DefDef` instances.
* @group Extractors
@@ -626,8 +564,28 @@ trait Trees { self: Universe =>
* @group Extractors
*/
abstract class DefDefExtractor {
- def apply(mods: Modifiers, name: Name, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree): DefDef
- def unapply(defDef: DefDef): Option[(Modifiers, Name, List[TypeDef], List[List[ValDef]], Tree, Tree)]
+ def apply(mods: Modifiers, name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree): DefDef
+ def unapply(defDef: DefDef): Option[(Modifiers, TermName, List[TypeDef], List[List[ValDef]], Tree, Tree)]
+
+ /** @see [[InternalApi.defDef]] */
+ @deprecated("Use `internal.defDef` instead", "2.11.0")
+ def apply(sym: Symbol, mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree)(implicit token: CompatToken): DefDef = internal.defDef(sym, mods, vparamss, rhs)
+
+ /** @see [[InternalApi.defDef]] */
+ @deprecated("Use `internal.defDef` instead", "2.11.0")
+ def apply(sym: Symbol, vparamss: List[List[ValDef]], rhs: Tree)(implicit token: CompatToken): DefDef = internal.defDef(sym, vparamss, rhs)
+
+ /** @see [[InternalApi.defDef]] */
+ @deprecated("Use `internal.defDef` instead", "2.11.0")
+ def apply(sym: Symbol, mods: Modifiers, rhs: Tree)(implicit token: CompatToken): DefDef = internal.defDef(sym, mods, rhs)
+
+ /** @see [[InternalApi.defDef]] */
+ @deprecated("Use `internal.defDef` instead", "2.11.0")
+ def apply(sym: Symbol, rhs: Tree)(implicit token: CompatToken): DefDef = internal.defDef(sym, rhs)
+
+ /** @see [[InternalApi.defDef]] */
+ @deprecated("Use `internal.defDef` instead", "2.11.0")
+ def apply(sym: Symbol, rhs: List[List[Symbol]] => Tree)(implicit token: CompatToken): DefDef = internal.defDef(sym, rhs)
}
/** The API that all def defs support
@@ -638,7 +596,7 @@ trait Trees { self: Universe =>
def mods: Modifiers
/** @inheritdoc */
- def name: Name
+ def name: TermName
/** The type parameters of the method. */
def tparams: List[TypeDef]
@@ -658,13 +616,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type TypeDef >: Null <: MemberDef with TypeDefApi
-
- /** A tag that preserves the identity of the `TypeDef` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val TypeDefTag: ClassTag[TypeDef]
+ type TypeDef >: Null <: TypeDefApi with MemberDef
/** The constructor/extractor for `TypeDef` instances.
* @group Extractors
@@ -686,6 +638,14 @@ trait Trees { self: Universe =>
abstract class TypeDefExtractor {
def apply(mods: Modifiers, name: TypeName, tparams: List[TypeDef], rhs: Tree): TypeDef
def unapply(typeDef: TypeDef): Option[(Modifiers, TypeName, List[TypeDef], Tree)]
+
+ /** @see [[InternalApi.typeDef]] */
+ @deprecated("Use `internal.typeDef` instead", "2.11.0")
+ def apply(sym: Symbol, rhs: Tree)(implicit token: CompatToken): TypeDef = internal.typeDef(sym, rhs)
+
+ /** @see [[InternalApi.typeDef]] */
+ @deprecated("Use `internal.typeDef` instead", "2.11.0")
+ def apply(sym: Symbol)(implicit token: CompatToken): TypeDef = internal.typeDef(sym)
}
/** The API that all type defs support
@@ -723,13 +683,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type LabelDef >: Null <: DefTree with TermTree with LabelDefApi
-
- /** A tag that preserves the identity of the `LabelDef` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val LabelDefTag: ClassTag[LabelDef]
+ type LabelDef >: Null <: LabelDefApi with DefTree with TermTree
/** The constructor/extractor for `LabelDef` instances.
* @group Extractors
@@ -752,6 +706,10 @@ trait Trees { self: Universe =>
abstract class LabelDefExtractor {
def apply(name: TermName, params: List[Ident], rhs: Tree): LabelDef
def unapply(labelDef: LabelDef): Option[(TermName, List[Ident], Tree)]
+
+ /** @see [[InternalApi.labelDef]] */
+ @deprecated("Use `internal.labelDef` instead", "2.11.0")
+ def apply(sym: Symbol, params: List[Symbol], rhs: Tree)(implicit token: CompatToken): LabelDef = internal.labelDef(sym, params, rhs)
}
/** The API that all label defs support
@@ -772,7 +730,7 @@ trait Trees { self: Universe =>
def rhs: Tree
}
- /** Import selector
+ /** Import selector (not a tree, but a component of the `Import` tree)
*
* Representation of an imported name its optional rename and their optional positions
*
@@ -787,12 +745,6 @@ trait Trees { self: Universe =>
*/
type ImportSelector >: Null <: AnyRef with ImportSelectorApi
- /** A tag that preserves the identity of the `ImportSelector` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ImportSelectorTag: ClassTag[ImportSelector]
-
/** The constructor/extractor for `ImportSelector` instances.
* @group Extractors
*/
@@ -837,13 +789,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Import >: Null <: SymTree with ImportApi
-
- /** A tag that preserves the identity of the `Import` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ImportTag: ClassTag[Import]
+ type Import >: Null <: ImportApi with SymTree
/** The constructor/extractor for `Import` instances.
* @group Extractors
@@ -895,13 +841,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Template >: Null <: SymTree with TemplateApi
-
- /** A tag that preserves the identity of the `Template` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val TemplateTag: ClassTag[Template]
+ type Template >: Null <: TemplateApi with SymTree
/** The constructor/extractor for `Template` instances.
* @group Extractors
@@ -940,7 +880,7 @@ trait Trees { self: Universe =>
def parents: List[Tree]
/** Self type of the template.
- * Is equal to `emptyValDef` if the self type is not specified.
+ * Is equal to `noSelfType` if the self type is not specified.
*/
def self: ValDef
@@ -953,13 +893,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Block >: Null <: TermTree with BlockApi
-
- /** A tag that preserves the identity of the `Block` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val BlockTag: ClassTag[Block]
+ type Block >: Null <: BlockApi with TermTree
/** The constructor/extractor for `Block` instances.
* @group Extractors
@@ -998,13 +932,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type CaseDef >: Null <: AnyRef with Tree with CaseDefApi
-
- /** A tag that preserves the identity of the `CaseDef` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val CaseDefTag: ClassTag[CaseDef]
+ type CaseDef >: Null <: CaseDefApi with Tree
/** The constructor/extractor for `CaseDef` instances.
* @group Extractors
@@ -1017,7 +945,7 @@ trait Trees { self: Universe =>
* `case` pat `if` guard => body
*
* If the guard is not present, the `guard` is set to `EmptyTree`.
- * If the body is not specified, the `body` is set to `Literal(Constant())`
+ * If the body is not specified, the `body` is set to `Literal(Constant(()))`
* @group Extractors
*/
abstract class CaseDefExtractor {
@@ -1038,7 +966,7 @@ trait Trees { self: Universe =>
def guard: Tree
/** The body of the pattern matching clause.
- * Is equal to `Literal(Constant())` if the body is not specified.
+ * Is equal to `Literal(Constant(()))` if the body is not specified.
*/
def body: Tree
}
@@ -1051,13 +979,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Alternative >: Null <: TermTree with AlternativeApi
-
- /** A tag that preserves the identity of the `Alternative` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val AlternativeTag: ClassTag[Alternative]
+ type Alternative >: Null <: AlternativeApi with TermTree
/** The constructor/extractor for `Alternative` instances.
* @group Extractors
@@ -1089,13 +1011,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Star >: Null <: TermTree with StarApi
-
- /** A tag that preserves the identity of the `Star` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val StarTag: ClassTag[Star]
+ type Star >: Null <: StarApi with TermTree
/** The constructor/extractor for `Star` instances.
* @group Extractors
@@ -1130,13 +1046,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Bind >: Null <: DefTree with BindApi
-
- /** A tag that preserves the identity of the `Bind` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val BindTag: ClassTag[Bind]
+ type Bind >: Null <: BindApi with DefTree
/** The constructor/extractor for `Bind` instances.
* @group Extractors
@@ -1187,7 +1097,7 @@ trait Trees { self: Universe =>
* UnApply(
* // a dummy node that carries the type of unapplication to patmat
* // the <unapply-selector> here doesn't have an underlying symbol
- * // it only has a type assigned, therefore after `resetAllAttrs` this tree is no longer typeable
+ * // it only has a type assigned, therefore after `untypecheck` this tree is no longer typeable
* Apply(Select(Ident(Foo), newTermName("unapply")), List(Ident(newTermName("<unapply-selector>")))),
* // arguments of the unapply => nothing synthetic here
* List(Bind(newTermName("x"), Ident(nme.WILDCARD)))),
@@ -1199,13 +1109,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type UnApply >: Null <: TermTree with UnApplyApi
-
- /** A tag that preserves the identity of the `UnApply` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val UnApplyTag: ClassTag[UnApply]
+ type UnApply >: Null <: UnApplyApi with TermTree
/** The constructor/extractor for `UnApply` instances.
* @group Extractors
@@ -1241,13 +1145,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Function >: Null <: TermTree with SymTree with FunctionApi
-
- /** A tag that preserves the identity of the `Function` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val FunctionTag: ClassTag[Function]
+ type Function >: Null <: FunctionApi with TermTree with SymTree
/** The constructor/extractor for `Function` instances.
* @group Extractors
@@ -1285,13 +1183,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Assign >: Null <: TermTree with AssignApi
-
- /** A tag that preserves the identity of the `Assign` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val AssignTag: ClassTag[Assign]
+ type Assign >: Null <: AssignApi with TermTree
/** The constructor/extractor for `Assign` instances.
* @group Extractors
@@ -1327,13 +1219,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type AssignOrNamedArg >: Null <: TermTree with AssignOrNamedArgApi
-
- /** A tag that preserves the identity of the `AssignOrNamedArg` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val AssignOrNamedArgTag: ClassTag[AssignOrNamedArg]
+ type AssignOrNamedArg >: Null <: AssignOrNamedArgApi with TermTree
/** The constructor/extractor for `AssignOrNamedArg` instances.
* @group Extractors
@@ -1374,13 +1260,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type If >: Null <: TermTree with IfApi
-
- /** A tag that preserves the identity of the `If` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val IfTag: ClassTag[If]
+ type If >: Null <: IfApi with TermTree
/** The constructor/extractor for `If` instances.
* @group Extractors
@@ -1431,13 +1311,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Match >: Null <: TermTree with MatchApi
-
- /** A tag that preserves the identity of the `Match` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val MatchTag: ClassTag[Match]
+ type Match >: Null <: MatchApi with TermTree
/** The constructor/extractor for `Match` instances.
* @group Extractors
@@ -1472,13 +1346,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Return >: Null <: TermTree with SymTree with ReturnApi
-
- /** A tag that preserves the identity of the `Return` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ReturnTag: ClassTag[Return]
+ type Return >: Null <: ReturnApi with SymTree with TermTree
/** The constructor/extractor for `Return` instances.
* @group Extractors
@@ -1510,13 +1378,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Try >: Null <: TermTree with TryApi
-
- /** A tag that preserves the identity of the `Try` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val TryTag: ClassTag[Try]
+ type Try >: Null <: TryApi with TermTree
/** The constructor/extractor for `Try` instances.
* @group Extractors
@@ -1554,13 +1416,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Throw >: Null <: TermTree with ThrowApi
-
- /** A tag that preserves the identity of the `Throw` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ThrowTag: ClassTag[Throw]
+ type Throw >: Null <: ThrowApi with TermTree
/** The constructor/extractor for `Throw` instances.
* @group Extractors
@@ -1590,13 +1446,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type New >: Null <: TermTree with NewApi
-
- /** A tag that preserves the identity of the `New` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val NewTag: ClassTag[New]
+ type New >: Null <: NewApi with TermTree
/** The constructor/extractor for `New` instances.
* @group Extractors
@@ -1646,13 +1496,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Typed >: Null <: TermTree with TypedApi
-
- /** A tag that preserves the identity of the `Typed` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val TypedTag: ClassTag[Typed]
+ type Typed >: Null <: TypedApi with TermTree
/** The constructor/extractor for `Typed` instances.
* @group Extractors
@@ -1685,13 +1529,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type GenericApply >: Null <: TermTree with GenericApplyApi
-
- /** A tag that preserves the identity of the `GenericApply` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val GenericApplyTag: ClassTag[GenericApply]
+ type GenericApply >: Null <: GenericApplyApi with TermTree
/** The API that all applies support
* @group API
@@ -1712,13 +1550,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type TypeApply >: Null <: GenericApply with TypeApplyApi
-
- /** A tag that preserves the identity of the `TypeApply` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val TypeApplyTag: ClassTag[TypeApply]
+ type TypeApply >: Null <: TypeApplyApi with GenericApply
/** The constructor/extractor for `TypeApply` instances.
* @group Extractors
@@ -1756,13 +1588,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Apply >: Null <: GenericApply with ApplyApi
-
- /** A tag that preserves the identity of the `Apply` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ApplyTag: ClassTag[Apply]
+ type Apply >: Null <: ApplyApi with GenericApply
/** The constructor/extractor for `Apply` instances.
* @group Extractors
@@ -1799,13 +1625,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Super >: Null <: TermTree with SuperApi
-
- /** A tag that preserves the identity of the `Super` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val SuperTag: ClassTag[Super]
+ type Super >: Null <: SuperApi with TermTree
/** The constructor/extractor for `Super` instances.
* @group Extractors
@@ -1851,13 +1671,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type This >: Null <: TermTree with SymTree with ThisApi
-
- /** A tag that preserves the identity of the `This` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ThisTag: ClassTag[This]
+ type This >: Null <: ThisApi with TermTree with SymTree
/** The constructor/extractor for `This` instances.
* @group Extractors
@@ -1892,13 +1706,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Select >: Null <: RefTree with SelectApi
-
- /** A tag that preserves the identity of the `Select` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val SelectTag: ClassTag[Select]
+ type Select >: Null <: SelectApi with RefTree
/** The constructor/extractor for `Select` instances.
* @group Extractors
@@ -1937,13 +1745,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Ident >: Null <: RefTree with IdentApi
-
- /** A tag that preserves the identity of the `Ident` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val IdentTag: ClassTag[Ident]
+ type Ident >: Null <: IdentApi with RefTree
/** The constructor/extractor for `Ident` instances.
* @group Extractors
@@ -1968,77 +1770,18 @@ trait Trees { self: Universe =>
* @group API
*/
trait IdentApi extends RefTreeApi { this: Ident =>
+ /** Was this ident created from a backquoted identifier? */
+ def isBackquoted: Boolean
+
/** @inheritdoc */
def name: Name
}
- /** Marks underlying reference to id as boxed.
- *
- * <b>Precondition:<\b> id must refer to a captured variable
- * A reference such marked will refer to the boxed entity, no dereferencing
- * with `.elem` is done on it.
- * This tree node can be emitted by macros such as reify that call referenceCapturedVariable.
- * It is eliminated in LambdaLift, where the boxing conversion takes place.
- * @group Trees
- * @template
- */
- type ReferenceToBoxed >: Null <: TermTree with ReferenceToBoxedApi
-
- /** A tag that preserves the identity of the `ReferenceToBoxed` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ReferenceToBoxedTag: ClassTag[ReferenceToBoxed]
-
- /** The constructor/extractor for `ReferenceToBoxed` instances.
- * @group Extractors
- */
- val ReferenceToBoxed: ReferenceToBoxedExtractor
-
- /** An extractor class to create and pattern match with syntax `ReferenceToBoxed(ident)`.
- * This AST node does not have direct correspondence to Scala code,
- * and is emitted by macros to reference capture vars directly without going through `elem`.
- *
- * For example:
- *
- * var x = ...
- * fun { x }
- *
- * Will emit:
- *
- * Ident(x)
- *
- * Which gets transformed to:
- *
- * Select(Ident(x), "elem")
- *
- * If `ReferenceToBoxed` were used instead of Ident, no transformation would be performed.
- * @group Extractors
- */
- abstract class ReferenceToBoxedExtractor {
- def apply(ident: Ident): ReferenceToBoxed
- def unapply(referenceToBoxed: ReferenceToBoxed): Option[Ident]
- }
-
- /** The API that all references support
- * @group API
- */
- trait ReferenceToBoxedApi extends TermTreeApi { this: ReferenceToBoxed =>
- /** The underlying reference. */
- def ident: Tree
- }
-
/** Literal
* @group Trees
* @template
*/
- type Literal >: Null <: TermTree with LiteralApi
-
- /** A tag that preserves the identity of the `Literal` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val LiteralTag: ClassTag[Literal]
+ type Literal >: Null <: LiteralApi with TermTree
/** The constructor/extractor for `Literal` instances.
* @group Extractors
@@ -2071,13 +1814,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type Annotated >: Null <: AnyRef with Tree with AnnotatedApi
-
- /** A tag that preserves the identity of the `Annotated` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val AnnotatedTag: ClassTag[Annotated]
+ type Annotated >: Null <: AnnotatedApi with Tree
/** The constructor/extractor for `Annotated` instances.
* @group Extractors
@@ -2111,13 +1848,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type SingletonTypeTree >: Null <: TypTree with SingletonTypeTreeApi
-
- /** A tag that preserves the identity of the `SingletonTypeTree` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val SingletonTypeTreeTag: ClassTag[SingletonTypeTree]
+ type SingletonTypeTree >: Null <: SingletonTypeTreeApi with TypTree
/** The constructor/extractor for `SingletonTypeTree` instances.
* @group Extractors
@@ -2147,13 +1878,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type SelectFromTypeTree >: Null <: TypTree with RefTree with SelectFromTypeTreeApi
-
- /** A tag that preserves the identity of the `SelectFromTypeTree` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val SelectFromTypeTreeTag: ClassTag[SelectFromTypeTree]
+ type SelectFromTypeTree >: Null <: SelectFromTypeTreeApi with TypTree with RefTree
/** The constructor/extractor for `SelectFromTypeTree` instances.
* @group Extractors
@@ -2194,13 +1919,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type CompoundTypeTree >: Null <: TypTree with CompoundTypeTreeApi
-
- /** A tag that preserves the identity of the `CompoundTypeTree` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val CompoundTypeTreeTag: ClassTag[CompoundTypeTree]
+ type CompoundTypeTree >: Null <: CompoundTypeTreeApi with TypTree
/** The constructor/extractor for `CompoundTypeTree` instances.
* @group Extractors
@@ -2230,13 +1949,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type AppliedTypeTree >: Null <: TypTree with AppliedTypeTreeApi
-
- /** A tag that preserves the identity of the `AppliedTypeTree` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val AppliedTypeTreeTag: ClassTag[AppliedTypeTree]
+ type AppliedTypeTree >: Null <: AppliedTypeTreeApi with TypTree
/** The constructor/extractor for `AppliedTypeTree` instances.
* @group Extractors
@@ -2278,13 +1991,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type TypeBoundsTree >: Null <: TypTree with TypeBoundsTreeApi
-
- /** A tag that preserves the identity of the `TypeBoundsTree` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val TypeBoundsTreeTag: ClassTag[TypeBoundsTree]
+ type TypeBoundsTree >: Null <: TypeBoundsTreeApi with TypTree
/** The constructor/extractor for `TypeBoundsTree` instances.
* @group Extractors
@@ -2321,13 +2028,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type ExistentialTypeTree >: Null <: TypTree with ExistentialTypeTreeApi
-
- /** A tag that preserves the identity of the `ExistentialTypeTree` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ExistentialTypeTreeTag: ClassTag[ExistentialTypeTree]
+ type ExistentialTypeTree >: Null <: ExistentialTypeTreeApi with TypTree
/** The constructor/extractor for `ExistentialTypeTree` instances.
* @group Extractors
@@ -2341,8 +2042,8 @@ trait Trees { self: Universe =>
* @group Extractors
*/
abstract class ExistentialTypeTreeExtractor {
- def apply(tpt: Tree, whereClauses: List[Tree]): ExistentialTypeTree
- def unapply(existentialTypeTree: ExistentialTypeTree): Option[(Tree, List[Tree])]
+ def apply(tpt: Tree, whereClauses: List[MemberDef]): ExistentialTypeTree
+ def unapply(existentialTypeTree: ExistentialTypeTree): Option[(Tree, List[MemberDef])]
}
/** The API that all existential type trees support
@@ -2352,8 +2053,12 @@ trait Trees { self: Universe =>
/** The underlying type of the existential type. */
def tpt: Tree
- /** The clauses of the definition of the existential type. */
- def whereClauses: List[Tree]
+ /** The clauses of the definition of the existential type.
+ * Elements are one of the following:
+ * 1) TypeDef with TypeBoundsTree right-hand side
+ * 2) ValDef with empty right-hand side
+ */
+ def whereClauses: List[MemberDef]
}
/** A synthetic tree holding an arbitrary type. Not to be confused with
@@ -2364,13 +2069,7 @@ trait Trees { self: Universe =>
* @group Trees
* @template
*/
- type TypeTree >: Null <: TypTree with TypeTreeApi
-
- /** A tag that preserves the identity of the `TypeTree` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val TypeTreeTag: ClassTag[TypeTree]
+ type TypeTree >: Null <: TypeTreeApi with TypTree
/** The constructor/extractor for `TypeTree` instances.
* @group Extractors
@@ -2403,93 +2102,33 @@ trait Trees { self: Universe =>
* no definition of a self value of self type.
* @group Trees
*/
- val emptyValDef: ValDef
-
-// ---------------------- factories ----------------------------------------------
-
- /** A factory method for `ClassDef` nodes.
- * @group Factories
- */
- @deprecated("Use the canonical ClassDef constructor to create a class and then initialize its position and symbol manually", "2.10.1")
- def ClassDef(sym: Symbol, impl: Template): ClassDef
-
- /** A factory method for `ModuleDef` nodes.
- * @group Factories
- */
- @deprecated("Use the canonical ModuleDef constructor to create an object and then initialize its position and symbol manually", "2.10.1")
- def ModuleDef(sym: Symbol, impl: Template): ModuleDef
-
- /** A factory method for `ValDef` nodes.
- * @group Factories
- */
- @deprecated("Use the canonical ValDef constructor to create a val and then initialize its position and symbol manually", "2.10.1")
- def ValDef(sym: Symbol, rhs: Tree): ValDef
-
- /** A factory method for `ValDef` nodes.
- * @group Factories
- */
- @deprecated("Use the canonical ValDef constructor to create a val with an empty right-hand side and then initialize its position and symbol manually", "2.10.1")
- def ValDef(sym: Symbol): ValDef
+ val noSelfType: ValDef
- /** A factory method for `ValDef` nodes.
- * @group Factories
- */
- @deprecated("Use the canonical DefDef constructor to create a method and then initialize its position and symbol manually", "2.10.1")
- def DefDef(sym: Symbol, mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree): DefDef
-
- /** A factory method for `ValDef` nodes.
- * @group Factories
- */
- @deprecated("Use the canonical DefDef constructor to create a method and then initialize its position and symbol manually", "2.10.1")
- def DefDef(sym: Symbol, vparamss: List[List[ValDef]], rhs: Tree): DefDef
-
- /** A factory method for `ValDef` nodes.
- * @group Factories
- */
- @deprecated("Use the canonical DefDef constructor to create a method and then initialize its position and symbol manually", "2.10.1")
- def DefDef(sym: Symbol, mods: Modifiers, rhs: Tree): DefDef
-
- /** A factory method for `ValDef` nodes.
- * @group Factories
- */
- @deprecated("Use the canonical DefDef constructor to create a method and then initialize its position and symbol manually", "2.10.1")
- def DefDef(sym: Symbol, rhs: Tree): DefDef
-
- /** A factory method for `ValDef` nodes.
- * @group Factories
- */
- @deprecated("Use the canonical DefDef constructor to create a method and then initialize its position and symbol manually", "2.10.1")
- def DefDef(sym: Symbol, rhs: List[List[Symbol]] => Tree): DefDef
-
- /** A factory method for `TypeDef` nodes.
- * @group Factories
- */
- @deprecated("Use the canonical TypeDef constructor to create a type alias and then initialize its position and symbol manually", "2.10.1")
- def TypeDef(sym: Symbol, rhs: Tree): TypeDef
+ @deprecated("Use `noSelfType` instead", "2.11.0")
+ val emptyValDef: ValDef
- /** A factory method for `TypeDef` nodes.
- * @group Factories
+ /** An empty superclass constructor call corresponding to:
+ * super.<init>()
+ * This is used as a placeholder in the primary constructor body in class templates
+ * to denote the insertion point of a call to superclass constructor after the typechecker
+ * figures out the superclass of a given template.
+ * @group Trees
*/
- @deprecated("Use the canonical TypeDef constructor to create an abstract type or type parameter and then initialize its position and symbol manually", "2.10.1")
- def TypeDef(sym: Symbol): TypeDef
+ val pendingSuperCall: Apply
- /** A factory method for `LabelDef` nodes.
- * @group Factories
- */
- @deprecated("Use the canonical LabelDef constructor to create a label and then initialize its position and symbol manually", "2.10.1")
- def LabelDef(sym: Symbol, params: List[Symbol], rhs: Tree): LabelDef
+// ---------------------- factories ----------------------------------------------
/** A factory method for `Block` nodes.
* Flattens directly nested blocks.
* @group Factories
*/
- @deprecated("Use the canonical Block constructor, explicitly specifying its expression if necessary. Flatten directly nested blocks manually if needed", "2.10.1")
+ @deprecated("Use q\"{..$stats}\" instead. Flatten directly nested blocks manually if needed", "2.10.1")
def Block(stats: Tree*): Block
/** A factory method for `CaseDef` nodes.
* @group Factories
*/
- @deprecated("Use the canonical CaseDef constructor passing EmptyTree for guard", "2.10.1")
+ @deprecated("Use cq\"$pat => $body\" instead", "2.10.1")
def CaseDef(pat: Tree, body: Tree): CaseDef
/** A factory method for `Bind` nodes.
@@ -2501,50 +2140,50 @@ trait Trees { self: Universe =>
/** A factory method for `Try` nodes.
* @group Factories
*/
- @deprecated("Use canonical CaseDef constructors to to create exception catching expressions and then wrap them in Try", "2.10.1")
+ @deprecated("Convert cases into casedefs and use q\"try $body catch { case ..$newcases }\" instead", "2.10.1")
def Try(body: Tree, cases: (Tree, Tree)*): Try
/** A factory method for `Throw` nodes.
* @group Factories
*/
- @deprecated("Use the canonical New constructor to create an object instantiation expression and then wrap it in Throw", "2.10.1")
+ @deprecated("Use q\"throw new $tpe(..$args)\" instead", "2.10.1")
def Throw(tpe: Type, args: Tree*): Throw
/** Factory method for object creation `new tpt(args_1)...(args_n)`
* A `New(t, as)` is expanded to: `(new t).<init>(as)`
* @group Factories
*/
- @deprecated("Use Apply(...Apply(Select(New(tpt), nme.CONSTRUCTOR), args1)...argsN) instead", "2.10.1")
+ @deprecated("Use q\"new $tpt(...$argss)\" instead", "2.10.1")
def New(tpt: Tree, argss: List[List[Tree]]): Tree
/** 0-1 argument list new, based on a type.
* @group Factories
*/
- @deprecated("Use New(TypeTree(tpe), args.toList) instead", "2.10.1")
+ @deprecated("Use q\"new $tpe(..$args)\" instead", "2.10.1")
def New(tpe: Type, args: Tree*): Tree
/** 0-1 argument list new, based on a symbol.
* @group Factories
*/
- @deprecated("Use New(sym.toType, args) instead", "2.10.1")
+ @deprecated("Use q\"new ${sym.toType}(..$args)\" instead", "2.10.1")
def New(sym: Symbol, args: Tree*): Tree
/** A factory method for `Apply` nodes.
* @group Factories
*/
- @deprecated("Use Apply(Ident(sym), args.toList) instead", "2.10.1")
+ @deprecated("Use q\"$sym(..$args)\" instead", "2.10.1")
def Apply(sym: Symbol, args: Tree*): Tree
/** 0-1 argument list new, based on a type tree.
* @group Factories
*/
- @deprecated("Use Apply(Select(New(tpt), nme.CONSTRUCTOR), args) instead", "2.10.1")
+ @deprecated("Use q\"new $tpt(..$args)\" instead", "2.10.1")
def ApplyConstructor(tpt: Tree, args: List[Tree]): Tree
/** A factory method for `Super` nodes.
* @group Factories
*/
- @deprecated("Use Super(This(sym), mix) instead", "2.10.1")
+ @deprecated("Use q\"$sym.super[$mix].x\".qualifier instead", "2.10.1")
def Super(sym: Symbol, mix: TypeName): Tree
/** A factory method for `This` nodes.
@@ -2556,7 +2195,7 @@ trait Trees { self: Universe =>
* The string `name` argument is assumed to represent a [[scala.reflect.api.Names#TermName `TermName`]].
* @group Factories
*/
- @deprecated("Use Select(tree, newTermName(name)) instead", "2.10.1")
+ @deprecated("Use Select(tree, TermName(name)) instead", "2.10.1")
def Select(qualifier: Tree, name: String): Select
/** A factory method for `Select` nodes.
@@ -2567,7 +2206,7 @@ trait Trees { self: Universe =>
/** A factory method for `Ident` nodes.
* @group Factories
*/
- @deprecated("Use Ident(newTermName(name)) instead", "2.10.1")
+ @deprecated("Use Ident(TermName(name)) instead", "2.10.1")
def Ident(name: String): Ident
/** A factory method for `Ident` nodes.
@@ -2586,7 +2225,7 @@ trait Trees { self: Universe =>
* @template
* @group Copying
*/
- type TreeCopier <: TreeCopierOps
+ type TreeCopier >: Null <: AnyRef with TreeCopierOps
/** The standard (lazy) tree copier.
* @group Copying
@@ -2762,6 +2401,11 @@ trait Trees { self: Universe =>
*/
def Ident(tree: Tree, name: Name): Ident
+ /** Creates a `RefTree` node from the given components, having a given `tree` as a prototype.
+ * Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
+ */
+ def RefTree(tree: Tree, qualifier: Tree, selector: Name): RefTree
+
/** Creates a `ReferenceToBoxed` node from the given components, having a given `tree` as a prototype.
* Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
*/
@@ -2810,7 +2454,7 @@ trait Trees { self: Universe =>
/** Creates a `ExistentialTypeTree` node from the given components, having a given `tree` as a prototype.
* Having a tree as a prototype means that the tree's attachments, type and symbol will be copied into the result.
*/
- def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[Tree]): ExistentialTypeTree
+ def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[MemberDef]): ExistentialTypeTree
}
// ---------------------- traversing and transforming ------------------------------
@@ -2821,18 +2465,32 @@ trait Trees { self: Universe =>
class Traverser {
protected[scala] var currentOwner: Symbol = rootMirror.RootClass
+ /** Traverse something which Trees contain, but which isn't a Tree itself. */
+ def traverseName(name: Name): Unit = ()
+ def traverseConstant(c: Constant): Unit = ()
+ def traverseImportSelector(sel: ImportSelector): Unit = ()
+ def traverseModifiers(mods: Modifiers): Unit = traverseAnnotations(mods.annotations)
+
/** Traverses a single tree. */
- def traverse(tree: Tree): Unit = itraverse(this, tree)
+ def traverse(tree: Tree): Unit = itraverse(this, tree)
+ def traversePattern(pat: Tree): Unit = traverse(pat)
+ def traverseGuard(guard: Tree): Unit = traverse(guard)
+ def traverseTypeAscription(tpt: Tree): Unit = traverse(tpt)
+ // Special handling of noSelfType necessary for backward compat: existing
+ // traversers break down when they see the unexpected tree.
+ def traverseSelfType(self: ValDef): Unit = if (self ne noSelfType) traverse(self)
/** Traverses a list of trees. */
- def traverseTrees(trees: List[Tree]) {
- trees foreach traverse
- }
+ def traverseTrees(trees: List[Tree]): Unit = trees foreach traverse
+ def traverseTypeArgs(args: List[Tree]): Unit = traverseTrees(args)
+ def traverseParents(parents: List[Tree]): Unit = traverseTrees(parents)
+ def traverseCases(cases: List[CaseDef]): Unit = traverseTrees(cases)
+ def traverseAnnotations(annots: List[Tree]): Unit = traverseTrees(annots)
/** Traverses a list of lists of trees. */
- def traverseTreess(treess: List[List[Tree]]) {
- treess foreach traverseTrees
- }
+ def traverseTreess(treess: List[List[Tree]]): Unit = treess foreach traverseTrees
+ def traverseParams(params: List[Tree]): Unit = traverseTrees(params)
+ def traverseParamss(vparamss: List[List[Tree]]): Unit = vparamss foreach traverseParams
/** Traverses a list of trees with a given owner symbol. */
def traverseStats(stats: List[Tree], exprOwner: Symbol) {
@@ -2897,7 +2555,8 @@ trait Trees { self: Universe =>
def transform(tree: Tree): Tree = itransform(this, tree)
/** Transforms a list of trees. */
- def transformTrees(trees: List[Tree]): List[Tree] = trees mapConserve (transform(_))
+ def transformTrees(trees: List[Tree]): List[Tree] =
+ if (trees.isEmpty) Nil else trees mapConserve transform
/** Transforms a `Template`. */
def transformTemplate(tree: Template): Template =
@@ -2907,7 +2566,8 @@ trait Trees { self: Universe =>
trees mapConserve (tree => transform(tree).asInstanceOf[TypeDef])
/** Transforms a `ValDef`. */
def transformValDef(tree: ValDef): ValDef =
- if (tree.isEmpty) tree else transform(tree).asInstanceOf[ValDef]
+ if (tree eq noSelfType) tree
+ else transform(tree).asInstanceOf[ValDef]
/** Transforms a list of `ValDef` nodes. */
def transformValDefs(trees: List[ValDef]): List[ValDef] =
trees mapConserve (transformValDef(_))
@@ -2915,6 +2575,8 @@ trait Trees { self: Universe =>
def transformValDefss(treess: List[List[ValDef]]): List[List[ValDef]] =
treess mapConserve (transformValDefs(_))
/** Transforms a list of `CaseDef` nodes. */
+ def transformMemberDefs(trees: List[MemberDef]): List[MemberDef] =
+ trees mapConserve (tree => transform(tree).asInstanceOf[MemberDef])
def transformCaseDefs(trees: List[CaseDef]): List[CaseDef] =
trees mapConserve (tree => transform(tree).asInstanceOf[CaseDef])
/** Transforms a list of `Ident` nodes. */
@@ -2926,8 +2588,10 @@ trait Trees { self: Universe =>
if (exprOwner != currentOwner && stat.isTerm) atOwner(exprOwner)(transform(stat))
else transform(stat)) filter (EmptyTree != _)
/** Transforms `Modifiers`. */
- def transformModifiers(mods: Modifiers): Modifiers =
- mods.mapAnnotations(transformTrees)
+ def transformModifiers(mods: Modifiers): Modifiers = {
+ if (mods.annotations.isEmpty) mods
+ else mods mapAnnotations transformTrees
+ }
/** Transforms a tree with a given owner symbol. */
def atOwner[A](owner: Symbol)(trans: => A): A = {
@@ -2951,17 +2615,11 @@ trait Trees { self: Universe =>
*/
protected def xtransform(transformer: Transformer, tree: Tree): Tree = throw new MatchError(tree)
- /** The type of tree modifiers.
+ /** The type of tree modifiers (not a tree, but rather part of DefTrees).
* @group Traversal
*/
type Modifiers >: Null <: AnyRef with ModifiersApi
- /** A tag that preserves the identity of the `Modifiers` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Traversal
- */
- implicit val ModifiersTag: ClassTag[Modifiers]
-
/** The API that all Modifiers support
* @group API
*/
@@ -2993,15 +2651,19 @@ trait Trees { self: Universe =>
/** The constructor/extractor for `Modifiers` instances.
* @group Traversal
*/
- val Modifiers: ModifiersCreator
+ val Modifiers: ModifiersExtractor
+
+ @deprecated("Use ModifiersExtractor instead", "2.11.0")
+ type ModifiersCreator = ModifiersExtractor
/** An extractor class to create and pattern match with syntax `Modifiers(flags, privateWithin, annotations)`.
* Modifiers encapsulate flags, visibility annotations and Scala annotations for member definitions.
* @group Traversal
*/
- abstract class ModifiersCreator {
+ abstract class ModifiersExtractor {
def apply(): Modifiers = Modifiers(NoFlags, tpnme.EMPTY, List())
def apply(flags: FlagSet, privateWithin: Name, annotations: List[Tree]): Modifiers
+ def unapply(mods: Modifiers): Option[(FlagSet, Name, List[Tree])]
}
/** The factory for `Modifiers` instances.
diff --git a/src/reflect/scala/reflect/api/TypeCreator.scala b/src/reflect/scala/reflect/api/TypeCreator.scala
index 24271cb48d..37fff90b43 100644
--- a/src/reflect/scala/reflect/api/TypeCreator.scala
+++ b/src/reflect/scala/reflect/api/TypeCreator.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package api
/** A mirror-aware factory for types.
diff --git a/src/reflect/scala/reflect/api/TypeTags.scala b/src/reflect/scala/reflect/api/TypeTags.scala
index 7457910226..1dfc84be69 100644
--- a/src/reflect/scala/reflect/api/TypeTags.scala
+++ b/src/reflect/scala/reflect/api/TypeTags.scala
@@ -134,7 +134,7 @@ import scala.language.implicitConversions
* reflection APIs provided by Java (for classes) and Scala (for types).</li>
*
* <li>'''Certain manifest operations(i.e., <:<, >:> and typeArguments) are not
- * supported.''' <br/>Instead, one culd use the reflection APIs provided by Java (for
+ * supported.''' <br/>Instead, one could use the reflection APIs provided by Java (for
* classes) and Scala (for types).</li>
*</ul>
*
@@ -333,6 +333,12 @@ trait TypeTags { self: Universe =>
* @group TypeTags
*/
def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpe
+
+ /**
+ * Type symbol of `x` as derived from a type tag.
+ * @group TypeTags
+ */
+ def symbolOf[T: WeakTypeTag]: TypeSymbol
}
private[scala] class SerializedTypeTag(var tpec: TypeCreator, var concrete: Boolean) extends Serializable {
diff --git a/src/reflect/scala/reflect/api/Types.scala b/src/reflect/scala/reflect/api/Types.scala
index 72163ef0e9..f6995dd5de 100644
--- a/src/reflect/scala/reflect/api/Types.scala
+++ b/src/reflect/scala/reflect/api/Types.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package api
/**
@@ -50,20 +51,15 @@ package api
*
* @contentDiagram hideNodes "*Api"
*/
-trait Types { self: Universe =>
+trait Types {
+ self: Universe =>
/** The type of Scala types, and also Scala type signatures.
* (No difference is internally made between the two).
* @template
* @group Types
*/
- type Type >: Null <: TypeApi
-
- /** A tag that preserves the identity of the `Type` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val TypeTagg: ClassTag[Type]
+ type Type >: Null <: AnyRef with TypeApi
/** This constant is used as a special value that indicates that no meaningful type exists.
* @group Types
@@ -80,6 +76,12 @@ trait Types { self: Universe =>
/** The API of types.
* The main source of information about types is the [[scala.reflect.api.Types]] page.
* @group API
+ *
+ * @define dealiasWidenWarning Note that type aliases can hide beneath
+ * singleton types and singleton types can hide inside type aliases.
+ * Moreover, aliases might lurk in the upper bounds of abstract types.
+ * Therefore careful thought has to be applied to identify and carry out
+ * unwrapping logic specific to your use case.
*/
abstract class TypeApi {
/** The term symbol associated with the type, or `NoSymbol` for types
@@ -92,11 +94,19 @@ trait Types { self: Universe =>
*/
def typeSymbol: Symbol
+ /** @see [[decl]] */
+ @deprecated("Use `decl` instead", "2.11.0")
+ def declaration(name: Name): Symbol
+
/** 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
+ def decl(name: Name): Symbol
+
+ /** @see [[decls]] */
+ @deprecated("Use `decls` instead", "2.11.0")
+ def declarations: MemberScope
/** A `Scope` containing directly declared members of this type.
* Unlike `members` this method doesn't returns inherited members.
@@ -104,7 +114,7 @@ trait Types { self: Universe =>
* Members in the returned scope might appear in arbitrary order.
* Use `declarations.sorted` to get an ordered list of members.
*/
- def declarations: MemberScope
+ def decls: MemberScope
/** The member with given name, either directly declared or inherited,
* an OverloadedSymbol if several exist, NoSymbol if none exist.
@@ -119,6 +129,11 @@ trait Types { self: Universe =>
*/
def members: MemberScope
+ /** Type signature of the companion of the underlying class symbol.
+ * NoType if the underlying symbol is not a class symbol, or if it doesn't have a companion.
+ */
+ def companion: Type
+
/** Is this type a type constructor that is missing its type arguments?
*/
def takesTypeArgs: Boolean
@@ -127,7 +142,7 @@ trait Types { self: Universe =>
*/
def typeConstructor: Type
- /**
+ /** 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.
*
@@ -135,8 +150,18 @@ trait Types { self: Universe =>
* TypeRef(pre, <List>, List()) is replaced by
* PolyType(X, TypeRef(pre, <List>, List(X)))
*/
+ @deprecated("Use `dealias` or `etaExpand` instead", "2.11.0")
def normalize: Type
+ /** 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 etaExpand: Type
+
/** Does this type conform to given type argument `that`? */
def <:< (that: Type): Boolean
@@ -209,11 +234,132 @@ trait Types { self: Universe =>
* class Outer { class C ; val x: C }
* val o: Outer
* <o.x.type>.widen = o.C
+ *
+ * $dealiasWidenWarning
*/
def widen: Type
+ /** Expands type aliases arising from type members.
+ * $dealiasWidenWarning
+ */
+ def dealias: Type
+
+ /******* popular methods from subclasses *******/
+
+ /** List of type arguments ingrained in this type reference.
+ * Depending on your use case you might or might not want to call `dealias` first.
+ *
+ * {{{
+ * scala> type T = List[Int]
+ * defined type alias T
+ *
+ * scala> typeOf[T].typeArgs
+ * res0: List[reflect.runtime.universe.Type] = List()
+ *
+ * scala> typeOf[T].dealias.typeArgs
+ * res1: List[reflect.runtime.universe.Type] = List(scala.Int)
+ * }}}
+ */
+ def typeArgs: List[Type]
+
+ /** @see [[paramLists]] */
+ @deprecated("Use `paramLists` instead", "2.11.0")
+ def paramss: List[List[Symbol]]
+
+ /** For a method or poly type, a list of its value parameter sections,
+ * the empty list of lists for all other types.
+ */
+ def paramLists: List[List[Symbol]]
+
+ /** For a poly type, its type parameters,
+ * the empty list for all other types.
+ */
+ def typeParams: List[Symbol]
+
+ /** For a (nullary) method or poly type, its direct result type
+ * (can be a MethodType if the method has multiple argument lists),
+ * the type itself for all other types.
+ *
+ * {{{
+ * scala> class C { def foo[T](x: T)(y: T) = ??? }
+ * defined class C
+ *
+ * scala> typeOf[C].member(TermName("foo")).asMethod
+ * res0: reflect.runtime.universe.MethodSymbol = method foo
+ *
+ * scala> res0.info // PolyType wrapping a MethodType
+ * res1: reflect.runtime.universe.Type = [T](x: T)(y: T)scala.Nothing
+ *
+ * scala> res1.resultType // MethodType wrapping a MethodType
+ * res2: reflect.runtime.universe.Type = (x: T)(y: T)scala.Nothing
+ *
+ * scala> res1.resultType.resultType // vanilla MethodType
+ * res3: reflect.runtime.universe.Type = (y: T)scala.Nothing
+ *
+ * scala> res1.resultType.resultType.resultType
+ * res4: reflect.runtime.universe.Type = scala.Nothing
+ *
+ * scala> res1.finalResultType
+ * res5: reflect.runtime.universe.Type = scala.Nothing
+ * }}}
+ *
+ * @see finalResultType
+ */
+ def resultType: Type
+
+ /** For a curried/nullary method or poly type its non-method result type,
+ * the type itself for all other types.
+ *
+ * {{{
+ * scala> class C {
+ * | def foo[T](x: T)(y: T) = ???
+ * | def bar: Int = ???
+ * | }
+ * defined class C
+ *
+ * scala> typeOf[C].member(TermName("foo")).asMethod
+ * res0: reflect.runtime.universe.MethodSymbol = method foo
+ *
+ * scala> res0.info // PolyType wrapping a MethodType
+ * res1: reflect.runtime.universe.Type = [T](x: T)(y: T)scala.Nothing
+ *
+ * scala> res1.resultType // MethodType wrapping a MethodType
+ * res2: reflect.runtime.universe.Type = (x: T)(y: T)scala.Nothing
+ *
+ * scala> res1.resultType.resultType // vanilla MethodType
+ * res3: reflect.runtime.universe.Type = (y: T)scala.Nothing
+ *
+ * scala> res1.resultType.resultType.resultType
+ * res4: reflect.runtime.universe.Type = scala.Nothing
+ *
+ * scala> res1.finalResultType
+ * res5: reflect.runtime.universe.Type = scala.Nothing
+ *
+ * scala> typeOf[C].member(TermName("bar")).asMethod
+ * res6: reflect.runtime.universe.MethodSymbol = method bar
+ *
+ * scala> res6.info
+ * res7: reflect.runtime.universe.Type = => scala.Int
+ *
+ * scala> res6.info.resultType
+ * res8: reflect.runtime.universe.Type = scala.Int
+ *
+ * scala> res6.info.finalResultType
+ * res9: reflect.runtime.universe.Type = scala.Int
+ * }}}
+ *
+ * @see resultType
+ */
+ def finalResultType: Type
+
/******************* helpers *******************/
+ /** Provides an alternate if type is NoType.
+ *
+ * @group Helpers
+ */
+ def orElse(alt: => Type): Type
+
/** Substitute symbols in `to` for corresponding occurrences of references to
* symbols `from` in this type.
*/
@@ -254,13 +400,12 @@ trait Types { self: Universe =>
* @template
* @group Types
*/
- type SingletonType >: Null <: Type
+ type SingletonType >: Null <: SingletonTypeApi with Type
- /** A tag that preserves the identity of the `SingletonType` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
+ /** Has no special methods. Is here to provides erased identity for `SingletonType`.
+ * @group API
*/
- implicit val SingletonTypeTag: ClassTag[SingletonType]
+ trait SingletonTypeApi
/** A singleton type that describes types of the form on the left with the
* corresponding `ThisType` representation to the right:
@@ -270,13 +415,7 @@ trait Types { self: Universe =>
* @template
* @group Types
*/
- type ThisType >: Null <: AnyRef with SingletonType with ThisTypeApi
-
- /** A tag that preserves the identity of the `ThisType` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ThisTypeTag: ClassTag[ThisType]
+ type ThisType >: Null <: ThisTypeApi with SingletonType
/** The constructor/extractor for `ThisType` instances.
* @group Extractors
@@ -288,11 +427,11 @@ trait Types { self: Universe =>
* @group Extractors
*/
abstract class ThisTypeExtractor {
- /**
- * Creates a ThisType from the given class symbol.
- */
- def apply(sym: Symbol): Type
def unapply(tpe: ThisType): Option[Symbol]
+
+ /** @see [[InternalApi.thisType]] */
+ @deprecated("Use `internal.thisType` instead", "2.11.0")
+ def apply(sym: Symbol)(implicit token: CompatToken): Type = internal.thisType(sym)
}
/** The API that all this types support.
@@ -314,13 +453,7 @@ trait Types { self: Universe =>
* @template
* @group Types
*/
- type SingleType >: Null <: AnyRef with SingletonType with SingleTypeApi
-
- /** A tag that preserves the identity of the `SingleType` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val SingleTypeTag: ClassTag[SingleType]
+ type SingleType >: Null <: SingleTypeApi with SingletonType
/** The constructor/extractor for `SingleType` instances.
* @group Extractors
@@ -333,8 +466,11 @@ trait Types { self: Universe =>
* @group Extractors
*/
abstract class SingleTypeExtractor {
- def apply(pre: Type, sym: Symbol): Type // not SingleTypebecause of implementation details
def unapply(tpe: SingleType): Option[(Type, Symbol)]
+
+ /** @see [[InternalApi.singleType]] */
+ @deprecated("Use `ClassSymbol.thisPrefix` or `internal.singleType` instead")
+ def apply(pre: Type, sym: Symbol)(implicit token: CompatToken): Type = internal.singleType(pre, sym)
}
/** The API that all single types support.
@@ -359,13 +495,7 @@ trait Types { self: Universe =>
* @template
* @group Types
*/
- type SuperType >: Null <: AnyRef with SingletonType with SuperTypeApi
-
- /** A tag that preserves the identity of the `SuperType` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val SuperTypeTag: ClassTag[SuperType]
+ type SuperType >: Null <: SuperTypeApi with SingletonType
/** The constructor/extractor for `SuperType` instances.
* @group Extractors
@@ -376,8 +506,11 @@ trait Types { self: Universe =>
* @group Extractors
*/
abstract class SuperTypeExtractor {
- def apply(thistpe: Type, supertpe: Type): Type // not SuperTypebecause of implementation details
def unapply(tpe: SuperType): Option[(Type, Type)]
+
+ /** @see [[InternalApi.superType]] */
+ @deprecated("Use `ClassSymbol.superPrefix` or `internal.superType` instead", "2.11.0")
+ def apply(thistpe: Type, supertpe: Type)(implicit token: CompatToken): Type = internal.superType(thistpe, supertpe)
}
/** The API that all super types support.
@@ -404,13 +537,7 @@ trait Types { self: Universe =>
* @template
* @group Types
*/
- type ConstantType >: Null <: AnyRef with SingletonType with ConstantTypeApi
-
- /** A tag that preserves the identity of the `ConstantType` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ConstantTypeTag: ClassTag[ConstantType]
+ type ConstantType >: Null <: ConstantTypeApi with SingletonType
/** The constructor/extractor for `ConstantType` instances.
* @group Extractors
@@ -422,8 +549,11 @@ trait Types { self: Universe =>
* @group Extractors
*/
abstract class ConstantTypeExtractor {
- def apply(value: Constant): ConstantType
def unapply(tpe: ConstantType): Option[Constant]
+
+ /** @see [[InternalApi.constantType]] */
+ @deprecated("Use `value.tpe` or `internal.constantType` instead", "2.11.0")
+ def apply(value: Constant)(implicit token: CompatToken): ConstantType = internal.constantType(value)
}
/** The API that all constant types support.
@@ -448,13 +578,7 @@ trait Types { self: Universe =>
* @template
* @group Types
*/
- type TypeRef >: Null <: AnyRef with Type with TypeRefApi
-
- /** A tag that preserves the identity of the `TypeRef` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val TypeRefTag: ClassTag[TypeRef]
+ type TypeRef >: Null <: TypeRefApi with Type
/** The constructor/extractor for `TypeRef` instances.
* @group Extractors
@@ -468,8 +592,11 @@ trait Types { self: Universe =>
* @group Extractors
*/
abstract class TypeRefExtractor {
- def apply(pre: Type, sym: Symbol, args: List[Type]): Type // not TypeRefbecause of implementation details
def unapply(tpe: TypeRef): Option[(Type, Symbol, List[Type])]
+
+ /** @see [[InternalApi.typeRef]] */
+ @deprecated("Use `internal.typeRef` instead", "2.11.0")
+ def apply(pre: Type, sym: Symbol, args: List[Type])(implicit token: CompatToken): Type = internal.typeRef(pre, sym, args)
}
/** The API that all type refs support.
@@ -495,13 +622,12 @@ trait Types { self: Universe =>
* @template
* @group Types
*/
- type CompoundType >: Null <: AnyRef with Type
+ type CompoundType >: Null <: CompoundTypeApi with Type
- /** A tag that preserves the identity of the `CompoundType` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
+ /** Has no special methods. Is here to provides erased identity for `CompoundType`.
+ * @group API
*/
- implicit val CompoundTypeTag: ClassTag[CompoundType]
+ trait CompoundTypeApi
/** The `RefinedType` type defines types of any of the forms on the left,
* with their RefinedType representations to the right.
@@ -513,13 +639,7 @@ trait Types { self: Universe =>
* @template
* @group Types
*/
- type RefinedType >: Null <: AnyRef with CompoundType with RefinedTypeApi
-
- /** A tag that preserves the identity of the `RefinedType` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val RefinedTypeTag: ClassTag[RefinedType]
+ type RefinedType >: Null <: RefinedTypeApi with CompoundType
/** The constructor/extractor for `RefinedType` instances.
* @group Extractors
@@ -532,13 +652,15 @@ trait Types { self: Universe =>
* @group Extractors
*/
abstract class RefinedTypeExtractor {
- def apply(parents: List[Type], decls: Scope): RefinedType
-
- /** An alternative constructor that passes in the synthetic classs symbol
- * that backs the refined type. (Normally, a fresh class symbol is created automatically).
- */
- def apply(parents: List[Type], decls: Scope, clazz: Symbol): RefinedType
def unapply(tpe: RefinedType): Option[(List[Type], Scope)]
+
+ /** @see [[InternalApi.refinedType]] */
+ @deprecated("Use `internal.refinedType` instead", "2.11.0")
+ def apply(parents: List[Type], decls: Scope)(implicit token: CompatToken): RefinedType = internal.refinedType(parents, decls)
+
+ /** @see [[InternalApi.refinedType]] */
+ @deprecated("Use `internal.refinedType` instead", "2.11.0")
+ def apply(parents: List[Type], decls: Scope, clazz: Symbol)(implicit token: CompatToken): RefinedType = internal.refinedType(parents, decls, clazz)
}
/** The API that all refined types support.
@@ -550,7 +672,7 @@ trait Types { self: Universe =>
def parents: List[Type]
/** The scope that holds the definitions comprising the type. */
- def decls: Scope
+ def decls: MemberScope
}
/** The `ClassInfo` type signature is used to define parents and declarations
@@ -565,13 +687,7 @@ trait Types { self: Universe =>
* @template
* @group Types
*/
- type ClassInfoType >: Null <: AnyRef with CompoundType with ClassInfoTypeApi
-
- /** A tag that preserves the identity of the `ClassInfoType` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ClassInfoTypeTag: ClassTag[ClassInfoType]
+ type ClassInfoType >: Null <: ClassInfoTypeApi with CompoundType
/** The constructor/extractor for `ClassInfoType` instances.
* @group Extractors
@@ -585,8 +701,11 @@ trait Types { self: Universe =>
* @group Extractors
*/
abstract class ClassInfoTypeExtractor {
- def apply(parents: List[Type], decls: Scope, typeSymbol: Symbol): ClassInfoType
def unapply(tpe: ClassInfoType): Option[(List[Type], Scope, Symbol)]
+
+ /** @see [[InternalApi.classInfoType]] */
+ @deprecated("Use `internal.classInfoType` instead", "2.11.0")
+ def apply(parents: List[Type], decls: Scope, typeSymbol: Symbol)(implicit token: CompatToken): ClassInfoType = internal.classInfoType(parents, decls, typeSymbol)
}
/** The API that all class info types support.
@@ -598,7 +717,7 @@ trait Types { self: Universe =>
def parents: List[Type]
/** The scope that holds the definitions comprising the class type. */
- def decls: Scope
+ def decls: MemberScope
/** The symbol underlying the class type. */
def typeSymbol: Symbol
@@ -608,13 +727,7 @@ trait Types { self: Universe =>
* @template
* @group Types
*/
- type MethodType >: Null <: AnyRef with Type with MethodTypeApi
-
- /** A tag that preserves the identity of the `MethodType` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val MethodTypeTag: ClassTag[MethodType]
+ type MethodType >: Null <: MethodTypeApi with Type
/** The constructor/extractor for `MethodType` instances.
* @group Extractors
@@ -637,8 +750,11 @@ trait Types { self: Universe =>
* @group Extractors
*/
abstract class MethodTypeExtractor {
- def apply(params: List[Symbol], resultType: Type): MethodType
def unapply(tpe: MethodType): Option[(List[Symbol], Type)]
+
+ /** @see [[InternalApi.methodType]] */
+ @deprecated("Use `internal.methodType` instead", "2.11.0")
+ def apply(params: List[Symbol], resultType: Type)(implicit token: CompatToken): MethodType = internal.methodType(params, resultType)
}
/** The API that all method types support.
@@ -658,13 +774,7 @@ trait Types { self: Universe =>
* @template
* @group Types
*/
- type NullaryMethodType >: Null <: AnyRef with Type with NullaryMethodTypeApi
-
- /** A tag that preserves the identity of the `NullaryMethodType` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val NullaryMethodTypeTag: ClassTag[NullaryMethodType]
+ type NullaryMethodType >: Null <: NullaryMethodTypeApi with Type
/** The constructor/extractor for `NullaryMethodType` instances.
* @group Extractors
@@ -676,8 +786,11 @@ trait Types { self: Universe =>
* @group Extractors
*/
abstract class NullaryMethodTypeExtractor {
- def apply(resultType: Type): NullaryMethodType
def unapply(tpe: NullaryMethodType): Option[(Type)]
+
+ /** @see [[InternalApi.nullaryMethodType]] */
+ @deprecated("Use `internal.nullaryMethodType` instead", "2.11.0")
+ def apply(resultType: Type)(implicit token: CompatToken): NullaryMethodType = internal.nullaryMethodType(resultType)
}
/** The API that all nullary method types support.
@@ -694,13 +807,7 @@ trait Types { self: Universe =>
* @template
* @group Types
*/
- type PolyType >: Null <: AnyRef with Type with PolyTypeApi
-
- /** A tag that preserves the identity of the `PolyType` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val PolyTypeTag: ClassTag[PolyType]
+ type PolyType >: Null <: PolyTypeApi with Type
/** The constructor/extractor for `PolyType` instances.
* @group Extractors
@@ -713,8 +820,11 @@ trait Types { self: Universe =>
* @group Extractors
*/
abstract class PolyTypeExtractor {
- def apply(typeParams: List[Symbol], resultType: Type): PolyType
def unapply(tpe: PolyType): Option[(List[Symbol], Type)]
+
+ /** @see [[InternalApi.polyType]] */
+ @deprecated("Use `internal.polyType` instead", "2.11.0")
+ def apply(typeParams: List[Symbol], resultType: Type)(implicit token: CompatToken): PolyType = internal.polyType(typeParams, resultType)
}
/** The API that all polymorphic types support.
@@ -734,13 +844,7 @@ trait Types { self: Universe =>
* @template
* @group Types
*/
- type ExistentialType >: Null <: AnyRef with Type with ExistentialTypeApi
-
- /** A tag that preserves the identity of the `ExistentialType` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val ExistentialTypeTag: ClassTag[ExistentialType]
+ type ExistentialType >: Null <: ExistentialTypeApi with Type
/** The constructor/extractor for `ExistentialType` instances.
* @group Extractors
@@ -754,8 +858,11 @@ trait Types { self: Universe =>
* @group Extractors
*/
abstract class ExistentialTypeExtractor {
- def apply(quantified: List[Symbol], underlying: Type): ExistentialType
def unapply(tpe: ExistentialType): Option[(List[Symbol], Type)]
+
+ /** @see [[InternalApi.existentialType]] */
+ @deprecated("Use `internal.existentialType` instead", "2.11.0")
+ def apply(quantified: List[Symbol], underlying: Type)(implicit token: CompatToken): ExistentialType = internal.existentialType(quantified, underlying)
}
/** The API that all existential types support.
@@ -775,13 +882,7 @@ trait Types { self: Universe =>
* @template
* @group Types
*/
- type AnnotatedType >: Null <: AnyRef with Type with AnnotatedTypeApi
-
- /** A tag that preserves the identity of the `AnnotatedType` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val AnnotatedTypeTag: ClassTag[AnnotatedType]
+ type AnnotatedType >: Null <: AnnotatedTypeApi with Type
/** The constructor/extractor for `AnnotatedType` instances.
* @group Extractors
@@ -789,14 +890,17 @@ trait Types { self: Universe =>
val AnnotatedType: AnnotatedTypeExtractor
/** An extractor class to create and pattern match with syntax
- * `AnnotatedType(annotations, underlying, selfsym)`.
+ * `AnnotatedType(annotations, underlying)`.
* Here, `annotations` are the annotations decorating the underlying type `underlying`.
* `selfSym` is a symbol representing the annotated type itself.
* @group Extractors
*/
abstract class AnnotatedTypeExtractor {
- def apply(annotations: List[Annotation], underlying: Type, selfsym: Symbol): AnnotatedType
- def unapply(tpe: AnnotatedType): Option[(List[Annotation], Type, Symbol)]
+ def unapply(tpe: AnnotatedType): Option[(List[Annotation], Type)]
+
+ /** @see [[InternalApi.annotatedType]] */
+ @deprecated("Use `internal.annotatedType` instead", "2.11.0")
+ def apply(annotations: List[Annotation], underlying: Type)(implicit token: CompatToken): AnnotatedType = internal.annotatedType(annotations, underlying)
}
/** The API that all annotated types support.
@@ -809,9 +913,6 @@ trait Types { self: Universe =>
/** The annotee. */
def underlying: Type
-
- /** A symbol that represents the annotated type itself. */
- def selfsym: Symbol
}
/** The `TypeBounds` type signature is used to indicate lower and upper type bounds
@@ -826,13 +927,7 @@ trait Types { self: Universe =>
* @template
* @group Types
*/
- type TypeBounds >: Null <: AnyRef with Type with TypeBoundsApi
-
- /** A tag that preserves the identity of the `TypeBounds` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val TypeBoundsTag: ClassTag[TypeBounds]
+ type TypeBounds >: Null <: TypeBoundsApi with Type
/** The constructor/extractor for `TypeBounds` instances.
* @group Extractors
@@ -845,8 +940,11 @@ trait Types { self: Universe =>
* @group Extractors
*/
abstract class TypeBoundsExtractor {
- def apply(lo: Type, hi: Type): TypeBounds
def unapply(tpe: TypeBounds): Option[(Type, Type)]
+
+ /** @see [[InternalApi.typeBounds]] */
+ @deprecated("Use `internal.typeBounds` instead", "2.11.0")
+ def apply(lo: Type, hi: Type)(implicit token: CompatToken): TypeBounds = internal.typeBounds(lo, hi)
}
/** The API that all type bounds support.
@@ -883,13 +981,7 @@ trait Types { self: Universe =>
* @template
* @group Types
*/
- type BoundedWildcardType >: Null <: AnyRef with Type with BoundedWildcardTypeApi
-
- /** A tag that preserves the identity of the `BoundedWildcardType` abstract type from erasure.
- * Can be used for pattern matching, instance tests, serialization and likes.
- * @group Tags
- */
- implicit val BoundedWildcardTypeTag: ClassTag[BoundedWildcardType]
+ type BoundedWildcardType >: Null <: BoundedWildcardTypeApi with Type
/** The constructor/extractor for `BoundedWildcardType` instances.
* @group Extractors
@@ -901,8 +993,11 @@ trait Types { self: Universe =>
* @group Extractors
*/
abstract class BoundedWildcardTypeExtractor {
- def apply(bounds: TypeBounds): BoundedWildcardType
def unapply(tpe: BoundedWildcardType): Option[TypeBounds]
+
+ /** @see [[InternalApi.boundedWildcardType]] */
+ @deprecated("Use `internal.boundedWildcardType` instead", "2.11.0")
+ def apply(bounds: TypeBounds)(implicit token: CompatToken): BoundedWildcardType = internal.boundedWildcardType(bounds)
}
/** The API that all this types support.
@@ -924,74 +1019,17 @@ trait Types { self: Universe =>
*/
def glb(ts: List[Type]): Type
- // Creators ---------------------------------------------------------------
- // too useful and too non-trivial to be left out of public API
-
- /** The canonical creator for single-types
- * @group TypeCreators
- */
- def singleType(pre: Type, sym: Symbol): Type
-
- /** the canonical creator for a refined type with a given scope
- * @group TypeCreators
- */
- def refinedType(parents: List[Type], owner: Symbol, decls: Scope, pos: Position): Type
-
- /** The canonical creator for a refined type with an initially empty scope.
- * @group TypeCreators
- */
- def refinedType(parents: List[Type], owner: Symbol): Type
-
- /** The canonical creator for typerefs
- * @group TypeCreators
- */
- 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.
- * @group TypeCreators
- */
- 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?
- * @group TypeCreators
- */
- def intersectionType(tps: List[Type], owner: Symbol): Type
-
/** A creator for type applications
- * @group Types
+ * @group TypeOps
*/
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).
- * @group Types
- */
- def polyType(tparams: List[Symbol], tpe: Type): Type
+ /** @see [[appliedType]] */
+ def appliedType(tycon: Type, args: 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`.
- * @group TypeCreators
- */
- def existentialAbstraction(tparams: List[Symbol], tpe0: Type): Type
+ /** @see [[appliedType]] */
+ def appliedType(sym: Symbol, args: List[Type]): Type
+
+ /** @see [[appliedType]] */
+ def appliedType(sym: Symbol, args: Type*): Type
}
diff --git a/src/reflect/scala/reflect/api/Universe.scala b/src/reflect/scala/reflect/api/Universe.scala
index 15fa11c6cf..a3d1d291eb 100644
--- a/src/reflect/scala/reflect/api/Universe.scala
+++ b/src/reflect/scala/reflect/api/Universe.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package api
/**
@@ -40,7 +41,8 @@ package api
* res1: reflect.runtime.universe.Type = scala.Either[String,Int]
* }}}
*
- * To obtain a `Universe` for use within a Scala macro, use [[scala.reflect.macros.Context#universe]]. For example:
+ * To obtain a `Universe` for use within a Scala macro, use [[scala.reflect.macros.blackbox.Context#universe]].
+ * or [[scala.reflect.macros.whitebox.Context#universe]]. For example:
* {{{
* def printf(format: String, params: Any*): Unit = macro impl
* def impl(c: Context)(format: c.Expr[String], params: c.Expr[Any]*): c.Expr[Unit] = {
@@ -67,13 +69,15 @@ abstract class Universe extends Symbols
with Positions
with Exprs
with TypeTags
- with TagInterop
+ with ImplicitTags
with StandardDefinitions
with StandardNames
- with BuildUtils
+ with StandardLiftables
with Mirrors
with Printers
- with Importers
+ with Liftables
+ with Quasiquotes
+ with Internals
{
/** Use `reify` to produce the abstract syntax tree representing a given Scala expression.
*
@@ -92,5 +96,5 @@ abstract class Universe extends Symbols
*/
// implementation is hardwired to `scala.reflect.reify.Taggers`
// using the mechanism implemented in `scala.tools.reflect.FastTrack`
- def reify[T](expr: T): Expr[T] = ??? // macro
+ def reify[T](expr: T): Expr[T] = macro ???
}
diff --git a/src/reflect/scala/reflect/api/package.scala b/src/reflect/scala/reflect/api/package.scala
index dbda84dd0e..a8f409e123 100644
--- a/src/reflect/scala/reflect/api/package.scala
+++ b/src/reflect/scala/reflect/api/package.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
import scala.reflect.api.{Universe => ApiUniverse}
@@ -42,6 +43,6 @@ package object api {
// implementation is hardwired into `scala.reflect.reify.Taggers`
// using the mechanism implemented in `scala.tools.reflect.FastTrack`
// todo. once we have implicit macros for tag generation, we can remove these anchors
- private[scala] def materializeWeakTypeTag[T](u: ApiUniverse): u.WeakTypeTag[T] = ??? // macro
- private[scala] def materializeTypeTag[T](u: ApiUniverse): u.TypeTag[T] = ??? // macro
+ private[scala] def materializeWeakTypeTag[T](u: ApiUniverse): u.WeakTypeTag[T] = macro ???
+ private[scala] def materializeTypeTag[T](u: ApiUniverse): u.TypeTag[T] = macro ???
} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/internal/AnnotationCheckers.scala b/src/reflect/scala/reflect/internal/AnnotationCheckers.scala
index 1ab975b233..74310e1c34 100644
--- a/src/reflect/scala/reflect/internal/AnnotationCheckers.scala
+++ b/src/reflect/scala/reflect/internal/AnnotationCheckers.scala
@@ -3,7 +3,8 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
/** Additions to the type checker that can be added at
@@ -52,7 +53,7 @@ trait AnnotationCheckers {
* given type tp, taking into account the given mode (see method adapt in trait Typers).
*/
@deprecated("Create an AnalyzerPlugin and use canAdaptAnnotations", "2.10.1")
- def canAdaptAnnotations(tree: Tree, mode: Int, pt: Type): Boolean = false
+ def canAdaptAnnotations(tree: Tree, mode: Mode, pt: Type): Boolean = false
/**
* Adapt a tree that has an annotated type to the given type tp, taking into account the given
@@ -62,7 +63,7 @@ trait AnnotationCheckers {
* class cannot do the adaptiong, it should return the tree unchanged.
*/
@deprecated("Create an AnalyzerPlugin and use adaptAnnotations", "2.10.1")
- def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree = tree
+ def adaptAnnotations(tree: Tree, mode: Mode, pt: Type): Tree = tree
/**
* Adapt the type of a return expression. The decision of a typer plugin whether the type
@@ -126,13 +127,13 @@ trait AnnotationCheckers {
else annotationCheckers.foldLeft(tpe)((tpe, checker) =>
if (!checker.isActive()) tpe else checker.addAnnotations(tree, tpe))
- def canAdaptAnnotations(tree: Tree, mode: Int, pt: Type): Boolean =
+ def canAdaptAnnotations(tree: Tree, mode: Mode, pt: Type): Boolean =
if (annotationCheckers.isEmpty) false
else annotationCheckers.exists(checker => {
checker.isActive() && checker.canAdaptAnnotations(tree, mode, pt)
})
- def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree =
+ def adaptAnnotations(tree: Tree, mode: Mode, pt: Type): Tree =
if (annotationCheckers.isEmpty) tree
else annotationCheckers.foldLeft(tree)((tree, checker) =>
if (!checker.isActive()) tree else checker.adaptAnnotations(tree, mode, pt))
diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
index 80b6b16d0a..f814a746f5 100644
--- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala
+++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
@@ -3,17 +3,19 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
-import util._
import pickling.ByteCodecs
import scala.annotation.tailrec
import scala.collection.immutable.ListMap
+import scala.language.postfixOps
/** AnnotationInfo and its helpers */
trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
- import definitions.{ ThrowsClass, StaticAnnotationClass, isMetaAnnotation }
+ import definitions._
+ import treeInfo._
// Common annotation code between Symbol and Type.
// For methods altering the annotation list, on Symbol it mutates
@@ -27,6 +29,8 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
def filterAnnotations(p: AnnotationInfo => Boolean): Self // Retain only annotations meeting the condition.
def withoutAnnotations: Self // Remove all annotations from this type.
+ def staticAnnotations = annotations filter (_.isStatic)
+
/** Symbols of any @throws annotations on this symbol.
*/
def throwsAnnotations(): List[Symbol] = annotations collect {
@@ -40,14 +44,13 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
// monomorphic one by introducing existentials, see SI-7009 for details
existentialAbstraction(throwableSym.typeParams, throwableSym.tpe)
}
- val throwsAnn = AnnotationInfo(appliedType(definitions.ThrowsClass, throwableTpe), List(Literal(Constant(throwableTpe))), Nil)
- withAnnotations(List(throwsAnn))
+ this withAnnotation AnnotationInfo(appliedType(ThrowsClass, throwableTpe), List(Literal(Constant(throwableTpe))), Nil)
}
/** Tests for, get, or remove an annotation */
def hasAnnotation(cls: Symbol): Boolean =
//OPT inlined from exists to save on #closures; was: annotations exists (_ matches cls)
- dropOtherAnnotations(annotations, cls).nonEmpty
+ dropOtherAnnotations(annotations, cls) ne Nil
def getAnnotation(cls: Symbol): Option[AnnotationInfo] =
//OPT inlined from exists to save on #closures; was: annotations find (_ matches cls)
@@ -74,7 +77,7 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
* - arrays of constants
* - or nested classfile annotations
*/
- abstract class ClassfileAnnotArg extends Product
+ sealed abstract class ClassfileAnnotArg extends Product with JavaArgumentApi
implicit val JavaArgumentTag = ClassTag[ClassfileAnnotArg](classOf[ClassfileAnnotArg])
case object UnmappableAnnotArg extends ClassfileAnnotArg
@@ -122,25 +125,32 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
* 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.
+ * Details about the storage format of pickles at the bytecode level (classfile annotations) can be found in SIP-10.
*/
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))
}
+
+ /* In order to store a byte array (the pickle) using a bytecode-level annotation,
+ * the most compact representation is used (which happens to be string-constant and not byte array as one would expect).
+ * However, a String constant in a classfile annotation is limited to a maximum of 65535 characters.
+ * Method `fitsInOneString` tells us whether the pickle can be held by a single classfile-annotation of string-type.
+ * Otherwise an array of strings will be used.
+ */
def fitsInOneString: Boolean = {
+ // due to escaping, a zero byte in a classfile-annotation of string-type takes actually two characters.
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
+
+ (sevenBitsMayBeZero.length + numZeros) <= 65535
}
+
def sigAnnot: Type =
- if (this.isLong)
- definitions.ScalaLongSignatureAnnotation.tpe
- else
+ if (fitsInOneString)
definitions.ScalaSignatureAnnotation.tpe
+ else
+ definitions.ScalaLongSignatureAnnotation.tpe
private def mapToNextModSevenBits(src: Array[Byte]): Array[Byte] = {
var i = 0
@@ -282,8 +292,8 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
* metaAnnotations = List(setter, field).
*/
def metaAnnotations: List[AnnotationInfo] = atp match {
- case AnnotatedType(metas, _, _) => metas
- case _ => Nil
+ case AnnotatedType(metas, _) => metas
+ case _ => Nil
}
/** The default kind of members to which this annotation is attached.
@@ -304,10 +314,6 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
/** 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 {
@@ -340,15 +346,74 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
}
implicit val AnnotationTag = ClassTag[AnnotationInfo](classOf[AnnotationInfo])
+ protected[scala] def annotationToTree(ann: Annotation): Tree = {
+ def reverseEngineerArgs(): List[Tree] = {
+ def reverseEngineerArg(jarg: ClassfileAnnotArg): Tree = jarg match {
+ case LiteralAnnotArg(const) =>
+ val tpe = if (const.tag == UnitTag) UnitTpe else ConstantType(const)
+ Literal(const) setType tpe
+ case ArrayAnnotArg(jargs) =>
+ val args = jargs map reverseEngineerArg
+ // TODO: I think it would be a good idea to typecheck Java annotations using a more traditional algorithm
+ // sure, we can't typecheck them as is using the `new jann(foo = bar)` syntax (because jann is going to be an @interface)
+ // however we can do better than `typedAnnotation` by desugaring the aforementioned expression to
+ // something like `new jann() { override def annotatedType() = ...; override def foo = bar }`
+ // and then using the results of that typecheck to produce a Java-compatible classfile entry
+ // in that case we're going to have correctly typed Array.apply calls, however that's 2.12 territory
+ // and for 2.11 exposing an untyped call to ArrayModule should suffice
+ Apply(Ident(ArrayModule), args.toList)
+ case NestedAnnotArg(ann: Annotation) =>
+ annotationToTree(ann)
+ case _ =>
+ EmptyTree
+ }
+ def reverseEngineerArgs(jargs: List[(Name, ClassfileAnnotArg)]): List[Tree] = jargs match {
+ case (name, jarg) :: rest => AssignOrNamedArg(Ident(name), reverseEngineerArg(jarg)) :: reverseEngineerArgs(rest)
+ case Nil => Nil
+ }
+ if (ann.javaArgs.isEmpty) ann.scalaArgs
+ else reverseEngineerArgs(ann.javaArgs.toList)
+ }
+
+ // TODO: at the moment, constructor selection is unattributed, because AnnotationInfos lack necessary information
+ // later on, in 2.12, for every annotation we could save an entire tree instead of just bits and pieces
+ // but for 2.11 the current situation will have to do
+ val ctorSelection = Select(New(TypeTree(ann.atp)), nme.CONSTRUCTOR)
+ Apply(ctorSelection, reverseEngineerArgs()) setType ann.atp
+ }
+
+ protected[scala] def treeToAnnotation(tree: Tree): Annotation = tree match {
+ case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) =>
+ def encodeJavaArg(arg: Tree): ClassfileAnnotArg = arg match {
+ case Literal(const) => LiteralAnnotArg(const)
+ case Apply(ArrayModule, args) => ArrayAnnotArg(args map encodeJavaArg toArray)
+ case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) => NestedAnnotArg(treeToAnnotation(arg))
+ case _ => throw new Exception("unexpected java argument shape $arg: literals, arrays and nested annotations are supported")
+ }
+ def encodeJavaArgs(args: List[Tree]): List[(Name, ClassfileAnnotArg)] = args match {
+ case AssignOrNamedArg(Ident(name), arg) :: rest => (name, encodeJavaArg(arg)) :: encodeJavaArgs(rest)
+ case arg :: rest => throw new Exception("unexpected java argument shape $arg: only AssignOrNamedArg trees are supported")
+ case Nil => Nil
+ }
+ val atp = tpt.tpe
+ if (atp != null && (atp.typeSymbol isNonBottomSubClass StaticAnnotationClass)) AnnotationInfo(atp, args, Nil)
+ else if (atp != null && (atp.typeSymbol isNonBottomSubClass ClassfileAnnotationClass)) AnnotationInfo(atp, Nil, encodeJavaArgs(args))
+ else throw new Exception(s"unexpected annotation type $atp: only subclasses of StaticAnnotation and ClassfileAnnotation are supported")
+ case _ =>
+ throw new Exception("""unexpected tree shape: only q"new $annType(..$args)" is supported""")
+ }
+
object UnmappableAnnotation extends CompleteAnnotationInfo(NoType, Nil, Nil)
+ object ErroneousAnnotation extends CompleteAnnotationInfo(ErrorType, Nil, Nil)
+
/** Extracts symbol of thrown exception from AnnotationInfo.
*
* Supports both “old-style” `@throws(classOf[Exception])`
* as well as “new-stye” `@throws[Exception]("cause")` annotations.
*/
object ThrownException {
- def unapply(ann: AnnotationInfo): Option[Symbol] =
+ def unapply(ann: AnnotationInfo): Option[Symbol] = {
ann match {
case AnnotationInfo(tpe, _, _) if tpe.typeSymbol != ThrowsClass =>
None
@@ -356,8 +421,11 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
case AnnotationInfo(_, List(Literal(Constant(tpe: Type))), _) =>
Some(tpe.typeSymbol)
// new-style: @throws[Exception], @throws[Exception]("cause")
- case AnnotationInfo(TypeRef(_, _, args), _, _) =>
- Some(args.head.typeSymbol)
+ case AnnotationInfo(TypeRef(_, _, arg :: _), _, _) =>
+ Some(arg.typeSymbol)
+ case AnnotationInfo(TypeRef(_, _, Nil), _, _) =>
+ Some(ThrowableClass)
}
+ }
}
}
diff --git a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
index 3c2b128c52..0ca8611719 100644
--- a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
+++ b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
@@ -2,7 +2,8 @@
* Copyright 2005-2013 LAMP/EPFL
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
// todo implement in terms of BitSet
@@ -37,7 +38,7 @@ trait BaseTypeSeqs {
* This is necessary because when run from reflection every base type sequence needs to have a
* SynchronizedBaseTypeSeq as mixin.
*/
- class BaseTypeSeq protected[BaseTypeSeqs] (private[BaseTypeSeqs] val parents: List[Type], private[BaseTypeSeqs] val elems: Array[Type]) {
+ class BaseTypeSeq protected[reflect] (private[BaseTypeSeqs] val parents: List[Type], private[BaseTypeSeqs] val elems: Array[Type]) {
self =>
if (Statistics.canEnable) Statistics.incCounter(baseTypeSeqCount)
if (Statistics.canEnable) Statistics.incCounter(baseTypeSeqLenTotal, elems.length)
@@ -64,16 +65,15 @@ trait BaseTypeSeqs {
//Console.println("compute closure of "+this+" => glb("+variants+")")
pending += i
try {
- mergePrefixAndArgs(variants, -1, lubDepth(variants)) match {
- case Some(tp0) =>
+ mergePrefixAndArgs(variants, Variance.Contravariant, lubDepth(variants)) match {
+ case NoType => typeError("no common type instance of base types "+(variants mkString ", and ")+" exists.")
+ case tp0 =>
pending(i) = false
elems(i) = tp0
tp0
- case None =>
- typeError(
- "no common type instance of base types "+(variants mkString ", and ")+" exists.")
}
- } catch {
+ }
+ catch {
case CyclicInheritance =>
typeError(
"computing the common type instance of base types "+(variants mkString ", and ")+" leads to a cycle.")
@@ -115,7 +115,7 @@ trait BaseTypeSeqs {
def map(f: Type => Type): BaseTypeSeq = {
// inlined `elems map f` for performance
val len = length
- var arr = new Array[Type](len)
+ val arr = new Array[Type](len)
var i = 0
while (i < len) {
arr(i) = f(elems(i))
@@ -130,9 +130,9 @@ trait BaseTypeSeqs {
lazy val maxDepth = maxDepthOfElems
- protected def maxDepthOfElems: Int = {
- var d = 0
- for (i <- 1 until length) d = max(d, typeDepth(elems(i)))
+ protected def maxDepthOfElems: Depth = {
+ var d = Depth.Zero
+ 1 until length foreach (i => d = d max typeDepth(elems(i)))
d
}
@@ -158,7 +158,7 @@ trait BaseTypeSeqs {
val parents = tp.parents
// Console.println("computing baseTypeSeq of " + tsym.tpe + " " + parents)//DEBUG
val buf = new mutable.ListBuffer[Type]
- buf += tsym.tpe
+ buf += tsym.tpe_*
var btsSize = 1
if (parents.nonEmpty) {
val nparents = parents.length
@@ -166,9 +166,10 @@ trait BaseTypeSeqs {
val index = new Array[Int](nparents)
var i = 0
for (p <- parents) {
+ val parentBts = p.dealias.baseTypeSeq // dealias need for SI-8046.
pbtss(i) =
- if (p.baseTypeSeq eq undetBaseTypeSeq) AnyClass.info.baseTypeSeq
- else p.baseTypeSeq
+ if (parentBts eq undetBaseTypeSeq) AnyClass.info.baseTypeSeq
+ else parentBts
index(i) = 0
i += 1
}
@@ -180,7 +181,7 @@ trait BaseTypeSeqs {
def nextRawElem(i: Int): Type = {
val j = index(i)
val pbts = pbtss(i)
- if (j < pbts.length) pbts.rawElem(j) else AnyClass.tpe
+ if (j < pbts.length) pbts.rawElem(j) else AnyTpe
}
var minSym: Symbol = NoSymbol
while (minSym != AnyClass) {
@@ -193,15 +194,23 @@ trait BaseTypeSeqs {
i += 1
}
var minTypes: List[Type] = List()
+ def alreadyInMinTypes(tp: Type): Boolean = {
+ @annotation.tailrec def loop(tps: List[Type]): Boolean = tps match {
+ case Nil => false
+ case x :: xs => (tp =:= x) || loop(xs)
+ }
+ loop(minTypes)
+ }
+
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
+ if (!alreadyInMinTypes(tp)) minTypes ::= tp
case tp =>
- if (!(minTypes exists (tp =:= _))) minTypes = tp :: minTypes
+ if (!alreadyInMinTypes(tp)) minTypes ::= tp
}
index(i) = index(i) + 1
}
@@ -226,7 +235,7 @@ trait BaseTypeSeqs {
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 => typeDepth(f(x))).max
+ override protected def maxDepthOfElems: Depth = elems.map(x => typeDepth(f(x))).max
override def toString = elems.mkString("MBTS(", ",", ")")
}
diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala
deleted file mode 100644
index 9f41f0336e..0000000000
--- a/src/reflect/scala/reflect/internal/BuildUtils.scala
+++ /dev/null
@@ -1,68 +0,0 @@
-package scala.reflect
-package internal
-
-import Flags._
-
-trait BuildUtils { self: SymbolTable =>
-
- class BuildImpl extends BuildApi {
-
- def selectType(owner: Symbol, name: String): TypeSymbol =
- select(owner, newTypeName(name)).asType
-
- def selectTerm(owner: Symbol, name: String): TermSymbol = {
- val result = select(owner, newTermName(name)).asTerm
- if (result.isOverloaded) result.suchThat(!_.isMethod).asTerm
- else result
- }
-
- private def select(owner: Symbol, name: Name): Symbol = {
- val result = owner.info decl name
- if (result ne NoSymbol) result
- else
- mirrorThatLoaded(owner).missingHook(owner, name) orElse
- MissingRequirementError.notFound("%s %s in %s".format(if (name.isTermName) "term" else "type", 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.asMethod
- else MissingRequirementError.notFound("overloaded method %s #%d in %s".format(name, index, owner.fullName))
- }
-
- def newFreeTerm(name: String, value: => Any, flags: Long = 0L, origin: String = null): FreeTermSymbol =
- newFreeTermSymbol(newTermName(name), value, flags, origin)
-
- def newFreeType(name: String, flags: Long = 0L, origin: String = null): FreeTypeSymbol =
- newFreeTypeSymbol(newTypeName(name), flags, 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: BuildApi = new BuildImpl
-}
diff --git a/src/reflect/scala/reflect/internal/CapturedVariables.scala b/src/reflect/scala/reflect/internal/CapturedVariables.scala
index a3d2a8bd94..ef9646b80f 100644
--- a/src/reflect/scala/reflect/internal/CapturedVariables.scala
+++ b/src/reflect/scala/reflect/internal/CapturedVariables.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package internal
import Flags._
@@ -19,7 +20,7 @@ trait CapturedVariables { self: SymbolTable =>
/** Convert type of a captured variable to *Ref type.
*/
def capturedVariableType(vble: Symbol): Type =
- capturedVariableType(vble, NoType, false)
+ capturedVariableType(vble, NoType, erasedTypes = false)
/** Convert type of a captured variable to *Ref type.
*/
diff --git a/src/reflect/scala/reflect/internal/Chars.scala b/src/reflect/scala/reflect/internal/Chars.scala
index 2d07092862..74413fdaba 100644
--- a/src/reflect/scala/reflect/internal/Chars.scala
+++ b/src/reflect/scala/reflect/internal/Chars.scala
@@ -2,7 +2,8 @@
* Copyright 2006-2013 LAMP/EPFL
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
import scala.annotation.{ tailrec, switch }
diff --git a/src/reflect/scala/reflect/internal/ClassfileConstants.scala b/src/reflect/scala/reflect/internal/ClassfileConstants.scala
index eb70ff3f17..e0a6757d34 100644
--- a/src/reflect/scala/reflect/internal/ClassfileConstants.scala
+++ b/src/reflect/scala/reflect/internal/ClassfileConstants.scala
@@ -3,13 +3,13 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
import scala.annotation.switch
object ClassfileConstants {
-
final val JAVA_MAGIC = 0xCAFEBABE
final val JAVA_MAJOR_VERSION = 45
final val JAVA_MINOR_VERSION = 3
@@ -340,7 +340,7 @@ object ClassfileConstants {
case JAVA_ACC_PRIVATE => PRIVATE
case JAVA_ACC_PROTECTED => PROTECTED
case JAVA_ACC_FINAL => FINAL
- case JAVA_ACC_SYNTHETIC => SYNTHETIC
+ case JAVA_ACC_SYNTHETIC => SYNTHETIC | ARTIFACT // maybe should be just artifact?
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
@@ -349,7 +349,7 @@ object ClassfileConstants {
private def translateFlags(jflags: Int, baseFlags: Long, isAnnotation: Boolean, isClass: Boolean): Long = {
def translateFlag0(jflags: Int): Long = translateFlag(jflags, isAnnotation, isClass)
var res: Long = JAVA | baseFlags
- /** fast, elegant, maintainable, pick any two... */
+ /* fast, elegant, maintainable, pick any two... */
res |= translateFlag0(jflags & JAVA_ACC_PRIVATE)
res |= translateFlag0(jflags & JAVA_ACC_PROTECTED)
res |= translateFlag0(jflags & JAVA_ACC_FINAL)
@@ -367,7 +367,7 @@ object ClassfileConstants {
translateFlags(jflags, if ((jflags & JAVA_ACC_FINAL) == 0) MUTABLE else 0 , isAnnotation(jflags), isClass = false)
}
def methodFlags(jflags: Int): Long = {
- translateFlags(jflags, if ((jflags & JAVA_ACC_BRIDGE) != 0) BRIDGE else 0, isAnnotation(jflags), isClass = false)
+ translateFlags(jflags, if ((jflags & JAVA_ACC_BRIDGE) != 0) BRIDGE | ARTIFACT else 0, isAnnotation(jflags), isClass = false)
}
}
object FlagTranslation extends FlagTranslation { }
@@ -375,11 +375,4 @@ object ClassfileConstants {
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
index 28bc3e1dd0..85d0efdcba 100644
--- a/src/reflect/scala/reflect/internal/Constants.scala
+++ b/src/reflect/scala/reflect/internal/Constants.scala
@@ -3,7 +3,8 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
import java.lang.Integer.toOctalString
@@ -62,17 +63,17 @@ trait Constants extends api.Constants {
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 UnitTag => UnitTpe
+ case BooleanTag => BooleanTpe
+ case ByteTag => ByteTpe
+ case ShortTag => ShortTpe
+ case CharTag => CharTpe
+ case IntTag => IntTpe
+ case LongTag => LongTpe
+ case FloatTag => FloatTpe
+ case DoubleTag => DoubleTpe
+ case StringTag => StringTpe
+ case NullTag => NullTpe
case ClazzTag => ClassType(typeValue)
case EnumTag => EnumType(symbolValue)
}
@@ -94,7 +95,7 @@ trait Constants extends api.Constants {
def booleanValue: Boolean =
if (tag == BooleanTag) value.asInstanceOf[Boolean]
- else throw new Error("value " + value + " is not a boolean");
+ else throw new Error("value " + value + " is not a boolean")
def byteValue: Byte = tag match {
case ByteTag => value.asInstanceOf[Byte]
@@ -211,7 +212,7 @@ trait Constants extends api.Constants {
case '"' => "\\\""
case '\'' => "\\\'"
case '\\' => "\\\\"
- case _ => if (ch.isControl) "\\0" + toOctalString(ch) else String.valueOf(ch)
+ case _ => if (ch.isControl) "\\0" + toOctalString(ch.toInt) else String.valueOf(ch)
}
def escapedStringValue: String = {
@@ -222,7 +223,15 @@ trait Constants extends api.Constants {
case ClazzTag =>
def show(tpe: Type) = "classOf[" + signature(tpe) + "]"
typeValue match {
- case ErasedValueType(orig) => show(orig)
+ case ErasedValueType(clazz, underlying) =>
+ // A note on tpe_* usage here:
+ //
+ // We've intentionally erased the type arguments to the value class so that different
+ // instantiations of a particular value class that erase to the same underlying type
+ // don't result in spurious bridges (e.g. run/t6385.scala). I don't think that matters;
+ // printing trees of `classOf[ValueClass[String]]` shows `classOf[ValueClass]` at phase
+ // erasure both before and after the use of `tpe_*` here.
+ show(clazz.tpe_*)
case _ => show(typeValue)
}
case CharTag => "'" + escapedChar(charValue) + "'"
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 09d7af82d1..bf560a21e5 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -3,19 +3,20 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
+import scala.language.postfixOps
import scala.annotation.{ switch, meta }
import scala.collection.{ mutable, immutable }
import Flags._
-import PartialFunction._
import scala.reflect.api.{Universe => ApiUniverse}
trait Definitions extends api.StandardDefinitions {
self: SymbolTable =>
- import rootMirror.{getModule, getClassByName, getRequiredClass, getRequiredModule, getRequiredPackage, getClassIfDefined, getModuleIfDefined, getPackageObject, getPackageObjectIfDefined, requiredClass, requiredModule}
+ import rootMirror.{getModuleByName, getPackage, getClassByName, getRequiredClass, getRequiredModule, getClassIfDefined, getModuleIfDefined, getPackageObject, getPackageIfDefined, getPackageObjectIfDefined, requiredClass, requiredModule}
object definitions extends DefinitionsClass
@@ -29,12 +30,13 @@ trait Definitions extends api.StandardDefinitions {
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)
+ clazz setInfoAndEnter ClassInfoType(parents, newScope, clazz) markAllCompleted
}
- private def newMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long = 0L): MethodSymbol = {
+ private def newMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long): MethodSymbol = {
val msym = owner.newMethod(name.encode, NoPosition, flags)
val params = msym.newSyntheticValueParams(formals)
- msym setInfo MethodType(params, restpe)
+ val info = if (owner.isJavaDefined) JavaMethodType(params, restpe) else MethodType(params, restpe)
+ msym setInfo info markAllCompleted
}
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)
@@ -67,7 +69,7 @@ trait Definitions extends api.StandardDefinitions {
tpnme.Unit -> VOID_TAG
)
- private def catastrophicFailure() =
+ private[Definitions] def catastrophicFailure() =
abort("Could not find value classes! This is a catastrophic failure. scala " +
scala.util.Properties.versionString)
@@ -77,16 +79,8 @@ trait Definitions extends api.StandardDefinitions {
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[Definitions] 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)
@@ -94,12 +88,10 @@ trait Definitions extends api.StandardDefinitions {
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 boxedModule = classesMap(x => getModuleByName(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)
@@ -124,19 +116,19 @@ trait Definitions extends api.StandardDefinitions {
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 UnitTpe = UnitClass.toTypeConstructor
- lazy val ByteTpe = ByteClass.toTypeConstructor
- lazy val ShortTpe = ShortClass.toTypeConstructor
- lazy val CharTpe = CharClass.toTypeConstructor
- lazy val IntTpe = IntClass.toTypeConstructor
- lazy val LongTpe = LongClass.toTypeConstructor
- lazy val FloatTpe = FloatClass.toTypeConstructor
- lazy val DoubleTpe = DoubleClass.toTypeConstructor
- lazy val BooleanTpe = BooleanClass.toTypeConstructor
+ def Boolean_and = getMemberMethod(BooleanClass, nme.ZAND)
+ def Boolean_or = getMemberMethod(BooleanClass, nme.ZOR)
+ def Boolean_not = getMemberMethod(BooleanClass, nme.UNARY_!)
+
+ lazy val UnitTpe = UnitClass.tpe
+ lazy val ByteTpe = ByteClass.tpe
+ lazy val ShortTpe = ShortClass.tpe
+ lazy val CharTpe = CharClass.tpe
+ lazy val IntTpe = IntClass.tpe
+ lazy val LongTpe = LongClass.tpe
+ lazy val FloatTpe = FloatClass.tpe
+ lazy val DoubleTpe = DoubleClass.tpe
+ lazy val BooleanTpe = BooleanClass.tpe
lazy val ScalaNumericValueClasses = ScalaValueClasses filterNot Set[Symbol](UnitClass, BooleanClass)
lazy val ScalaValueClassesNoUnit = ScalaValueClasses filterNot (_ eq UnitClass)
@@ -151,50 +143,26 @@ trait Definitions extends api.StandardDefinitions {
FloatClass,
DoubleClass
)
- def ScalaValueClassCompanions: List[Symbol] = ScalaValueClasses map (_.companionSymbol)
def ScalaPrimitiveValueClasses: List[ClassSymbol] = ScalaValueClasses
+
+ def underlyingOfValueClass(clazz: Symbol): Type =
+ clazz.derivedValueClassUnbox.tpe.resultType
+
}
abstract class DefinitionsClass extends DefinitionsApi with ValueClassDefinitions {
private var isInitialized = false
def isDefinitionsInitialized = isInitialized
- // symbols related to packages
- var emptypackagescope: Scope = null //debug
-
- @deprecated("Moved to rootMirror.RootPackage", "2.10.0")
- val RootPackage: ModuleSymbol = rootMirror.RootPackage
-
- @deprecated("Moved to rootMirror.RootClass", "2.10.0")
- val RootClass: ClassSymbol = rootMirror.RootClass
-
- @deprecated("Moved to rootMirror.EmptyPackage", "2.10.0")
- val EmptyPackage: ModuleSymbol = rootMirror.EmptyPackage
-
- @deprecated("Moved to rootMirror.EmptyPackageClass", "2.10.0")
- val EmptyPackageClass: ClassSymbol = rootMirror.EmptyPackageClass
-
// It becomes tricky to create dedicated objects for other symbols because
// of initialization order issues.
- lazy val JavaLangPackage = getRequiredPackage(sn.JavaLang)
+ lazy val JavaLangPackage = getPackage("java.lang")
lazy val JavaLangPackageClass = JavaLangPackage.moduleClass.asClass
- lazy val ScalaPackage = getRequiredPackage(nme.scala_)
+ lazy val ScalaPackage = getPackage("scala")
lazy val ScalaPackageClass = ScalaPackage.moduleClass.asClass
- lazy val RuntimePackage = getRequiredPackage("scala.runtime")
+ lazy val RuntimePackage = getPackage("scala.runtime")
lazy val RuntimePackageClass = RuntimePackage.moduleClass.asClass
- 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
@@ -224,61 +192,92 @@ trait Definitions extends api.StandardDefinitions {
*/
def fullyInitializeSymbol(sym: Symbol): Symbol = {
sym.initialize
+ // Watch out for those darn raw types on method parameters
+ if (sym.owner.initialize.isJavaDefined)
+ sym.cookJavaRawInfo()
+
fullyInitializeType(sym.info)
- fullyInitializeType(sym.tpe)
+ fullyInitializeType(sym.tpe_*)
sym
}
def fullyInitializeType(tp: Type): Type = {
tp.typeParams foreach fullyInitializeSymbol
- tp.paramss.flatten foreach fullyInitializeSymbol
+ mforeach(tp.paramss)(fullyInitializeSymbol)
tp
}
def fullyInitializeScope(scope: Scope): Scope = {
scope.sorted foreach fullyInitializeSymbol
scope
}
+ /** Is this symbol a member of Object or Any? */
+ def isUniversalMember(sym: Symbol) = ObjectClass isSubClass sym.owner
+
+ /** Is this symbol unimportable? Unimportable symbols include:
+ * - constructors, because <init> is not a real name
+ * - private[this] members, which cannot be referenced from anywhere else
+ * - members of Any or Object, because every instance will inherit a
+ * definition which supersedes the imported one
+ */
+ def isUnimportable(sym: Symbol) = (
+ (sym eq NoSymbol)
+ || sym.isConstructor
+ || sym.isPrivateLocal
+ )
+ def isUnimportableUnlessRenamed(sym: Symbol) = isUnimportable(sym) || isUniversalMember(sym)
+ def isImportable(sym: Symbol) = !isUnimportable(sym)
+
/** Is this type equivalent to Any, AnyVal, or AnyRef? */
def isTrivialTopType(tp: Type) = (
- tp =:= AnyClass.tpe
- || tp =:= AnyValClass.tpe
- || tp =:= AnyRefClass.tpe
+ tp =:= AnyTpe
+ || tp =:= AnyValTpe
+ || tp =:= AnyRefTpe
)
- /** Does this type have a parent which is none of Any, AnyVal, or AnyRef? */
- def hasNonTrivialParent(tp: Type) = tp.parents exists (t => !isTrivialTopType(tp))
+
+ def hasMultipleNonImplicitParamLists(member: Symbol): Boolean = hasMultipleNonImplicitParamLists(member.info)
+ def hasMultipleNonImplicitParamLists(info: Type): Boolean = info match {
+ case PolyType(_, restpe) => hasMultipleNonImplicitParamLists(restpe)
+ case MethodType(_, MethodType(p :: _, _)) if !p.isImplicit => true
+ case _ => false
+ }
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)
+ ClassInfoType(AnyTpe :: 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 AnyClass = enterNewClass(ScalaPackageClass, tpnme.Any, Nil, ABSTRACT) markAllCompleted
+ lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectTpe) markAllCompleted
lazy val ObjectClass = getRequiredClass(sn.Object.toString)
- lazy val AnyTpe = definitions.AnyClass.toTypeConstructor
- lazy val AnyRefTpe = definitions.AnyRefClass.toTypeConstructor
- lazy val ObjectTpe = definitions.ObjectClass.toTypeConstructor
- // 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
+ // Cached types for core monomorphic classes
+ lazy val AnyRefTpe = AnyRefClass.tpe
+ lazy val AnyTpe = AnyClass.tpe
+ lazy val AnyValTpe = AnyValClass.tpe
+ lazy val BoxedUnitTpe = BoxedUnitClass.tpe
+ lazy val NothingTpe = NothingClass.tpe
+ lazy val NullTpe = NullClass.tpe
+ lazy val ObjectTpe = ObjectClass.tpe
+ lazy val SerializableTpe = SerializableClass.tpe
+ lazy val StringTpe = StringClass.tpe
+ lazy val ThrowableTpe = ThrowableClass.tpe
+
+ lazy val ConstantTrue = ConstantType(Constant(true))
+ lazy val ConstantFalse = ConstantType(Constant(false))
+ lazy val ConstantNull = ConstantType(Constant(null))
lazy val AnyValClass: ClassSymbol = (ScalaPackageClass.info member tpnme.AnyVal orElse {
- val anyval = enterNewClass(ScalaPackageClass, tpnme.AnyVal, List(AnyClass.tpe, NotNullClass.tpe), ABSTRACT)
+ val anyval = enterNewClass(ScalaPackageClass, tpnme.AnyVal, AnyTpe :: Nil, ABSTRACT)
val av_constr = anyval.newClassConstructor(NoPosition)
anyval.info.decls enter av_constr
- anyval
+ anyval markAllCompleted
}).asInstanceOf[ClassSymbol]
- lazy val AnyValTpe = definitions.AnyValClass.toTypeConstructor
def AnyVal_getClass = getMemberMethod(AnyValClass, nme.getClass_)
// bottom types
@@ -289,8 +288,10 @@ trait Definitions extends api.StandardDefinitions {
locally {
this initFlags ABSTRACT | FINAL
this setInfoAndEnter ClassInfoType(List(parent.tpe), newScope, this)
+ this markAllCompleted
}
final override def isBottomClass = true
+ final override def isThreadsafe(purpose: SymbolOps): Boolean = true
}
final object NothingClass extends BottomClassSymbol(tpnme.Nothing, AnyClass) {
override def isSubClass(that: Symbol) = true
@@ -301,8 +302,6 @@ trait Definitions extends api.StandardDefinitions {
|| (that ne NothingClass) && (that isSubClass ObjectClass)
)
}
- lazy val NothingTpe = definitions.NothingClass.toTypeConstructor
- lazy val NullTpe = definitions.NullClass.toTypeConstructor
// exceptions and other throwables
lazy val ClassCastExceptionClass = requiredClass[ClassCastException]
@@ -314,6 +313,8 @@ trait Definitions extends api.StandardDefinitions {
lazy val ThrowableClass = getClassByName(sn.Throwable)
lazy val UninitializedErrorClass = requiredClass[UninitializedFieldError]
+ lazy val UninitializedFieldConstructor = UninitializedErrorClass.primaryConstructor
+
// fundamental reference classes
lazy val PartialFunctionClass = requiredClass[PartialFunction[_,_]]
lazy val AbstractPartialFunctionClass = requiredClass[scala.runtime.AbstractPartialFunction[_,_]]
@@ -336,22 +337,9 @@ trait Definitions extends api.StandardDefinitions {
// 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_wrapArray(tp: Type) = getMemberMethod(PredefModule, wrapArrayMethodName(tp))
- 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).
- */
+ lazy val PredefModule = requiredModule[scala.Predef.type]
+ def Predef_wrapArray(tp: Type) = getMemberMethod(PredefModule, wrapArrayMethodName(tp))
+ def Predef_??? = getMemberMethod(PredefModule, nme.???)
def isPredefMemberNamed(sym: Symbol, name: Name) = (
(sym.name == name) && (sym.owner == PredefModule.moduleClass)
)
@@ -359,50 +347,30 @@ trait Definitions extends api.StandardDefinitions {
/** 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 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)
+ def Symbol_apply = getMemberMethod(SymbolModule, nme.apply)
// 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 SingletonClass = enterNewClass(ScalaPackageClass, tpnme.Singleton, AnyTpe :: Nil, ABSTRACT | TRAIT | FINAL) markAllCompleted
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 CloneableClass = requiredClass[scala.Cloneable]
lazy val JavaCloneableClass = requiredClass[java.lang.Cloneable]
lazy val JavaNumberClass = requiredClass[java.lang.Number]
+ lazy val JavaEnumClass = requiredClass[java.lang.Enum[_]]
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 ByNameParamClass = specialPolyClass(tpnme.BYNAME_PARAM_CLASS_NAME, COVARIANT)(_ => AnyTpe)
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))
@@ -410,7 +378,8 @@ trait Definitions extends api.StandardDefinitions {
def isScalaRepeatedParamType(tp: Type) = tp.typeSymbol == RepeatedParamClass
def isJavaRepeatedParamType(tp: Type) = tp.typeSymbol == JavaRepeatedParamClass
def isRepeatedParamType(tp: Type) = isScalaRepeatedParamType(tp) || isJavaRepeatedParamType(tp)
- def isRepeated(param: Symbol) = isRepeatedParamType(param.tpe)
+ def isRepeated(param: Symbol) = isRepeatedParamType(param.tpe_*)
+ def isByName(param: Symbol) = isByNameParamType(param.tpe_*)
def isCastSymbol(sym: Symbol) = sym == Any_asInstanceOf || sym == Object_asInstanceOf
def isJavaVarArgsMethod(m: Symbol) = m.isMethod && isJavaVarArgs(m.info.params)
@@ -419,52 +388,49 @@ trait Definitions extends api.StandardDefinitions {
def isVarArgsList(params: Seq[Symbol]) = params.nonEmpty && isRepeatedParamType(params.last.tpe)
def isVarArgTypes(formals: Seq[Type]) = formals.nonEmpty && isRepeatedParamType(formals.last)
+ def firstParamType(tpe: Type): Type = tpe.paramTypes match {
+ case p :: _ => p
+ case _ => NoType
+ }
+ def isImplicitParamss(paramss: List[List[Symbol]]) = paramss match {
+ case (p :: _) :: _ => p.isImplicit
+ case _ => false
+ }
+
def hasRepeatedParam(tp: Type): Boolean = tp match {
case MethodType(formals, restpe) => isScalaVarArgs(formals) || hasRepeatedParam(restpe)
case PolyType(_, restpe) => hasRepeatedParam(restpe)
case _ => false
}
- def repeatedToSeq(tp: Type): Type = (tp baseType RepeatedParamClass) match {
- case TypeRef(_, RepeatedParamClass, arg :: Nil) => seqType(arg)
- case _ => tp
- }
-
- def seqToRepeated(tp: Type): Type = (tp baseType SeqClass) match {
- case TypeRef(_, SeqClass, arg :: Nil) => scalaRepeatedType(arg)
- case _ => tp
- }
-
- 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")
+ // wrapping and unwrapping
+ def dropByName(tp: Type): Type = elementExtract(ByNameParamClass, tp) orElse tp
+ def dropRepeated(tp: Type): Type = (
+ if (isJavaRepeatedParamType(tp)) elementExtract(JavaRepeatedParamClass, tp) orElse tp
+ else if (isScalaRepeatedParamType(tp)) elementExtract(RepeatedParamClass, tp) orElse tp
+ else tp
+ )
+ def repeatedToSingle(tp: Type): Type = elementExtract(RepeatedParamClass, tp) orElse elementExtract(JavaRepeatedParamClass, tp) orElse tp
+ // We don't need to deal with JavaRepeatedParamClass here, as `repeatedToSeq` is only called in the patmat translation for Scala sources.
+ def repeatedToSeq(tp: Type): Type = elementTransform(RepeatedParamClass, tp)(seqType) orElse tp
+ def seqToRepeated(tp: Type): Type = elementTransform(SeqClass, tp)(scalaRepeatedType) orElse tp
+ def isReferenceArray(tp: Type) = elementTest(ArrayClass, tp)(_ <:< AnyRefTpe)
+ def isArrayOfSymbol(tp: Type, elem: Symbol) = elementTest(ArrayClass, tp)(_.typeSymbol == elem)
+ def elementType(container: Symbol, tp: Type): Type = elementExtract(container, tp)
// 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 IterableClass = requiredClass[scala.collection.Iterable[_]]
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)
+ def 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]
@@ -479,47 +445,44 @@ trait Definitions extends api.StandardDefinitions {
// 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_)
+ // XML
+ lazy val ScalaXmlTopScope = getModuleIfDefined("scala.xml.TopScope")
+ lazy val ScalaXmlPackage = getPackageIfDefined("scala.xml")
+
// scala.reflect
lazy val ReflectPackage = requiredModule[scala.reflect.`package`.type]
lazy val ReflectApiPackage = getPackageObjectIfDefined("scala.reflect.api") // defined in scala-reflect.jar, so we need to be careful
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
+ def ReflectRuntimeUniverse = ReflectRuntimePackage.map(sym => getMemberValue(sym, nme.universe))
+ def ReflectRuntimeCurrentMirror = ReflectRuntimePackage.map(sym => getMemberMethod(sym, nme.currentMirror))
+
+ lazy val UniverseClass = getClassIfDefined("scala.reflect.api.Universe") // defined in scala-reflect.jar, so we need to be careful
+ def UniverseInternal = getMemberValue(UniverseClass, nme.internal)
- lazy val PartialManifestClass = getTypeMember(ReflectPackage, tpnme.ClassManifest)
lazy val PartialManifestModule = requiredModule[scala.reflect.ClassManifestFactory.type]
lazy val FullManifestClass = requiredClass[scala.reflect.Manifest[_]]
lazy val FullManifestModule = requiredModule[scala.reflect.ManifestFactory.type]
lazy val OptManifestClass = requiredClass[scala.reflect.OptManifest[_]]
lazy val NoManifest = requiredModule[scala.reflect.NoManifest.type]
+ lazy val TreesClass = getClassIfDefined("scala.reflect.api.Trees") // defined in scala-reflect.jar, so we need to be careful
+
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
+ def ExprClass = ExprsClass.map(sym => getMemberClass(sym, tpnme.Expr))
+ def ExprSplice = ExprClass.map(sym => getMemberMethod(sym, nme.splice))
+ def ExprValue = ExprClass.map(sym => getMemberMethod(sym, nme.value))
lazy val ClassTagModule = requiredModule[scala.reflect.ClassTag[_]]
lazy val ClassTagClass = requiredClass[scala.reflect.ClassTag[_]]
lazy val TypeTagsClass = getClassIfDefined("scala.reflect.api.TypeTags") // defined in scala-reflect.jar, so we need to be careful
- lazy val WeakTypeTagClass = if (TypeTagsClass != NoSymbol) getMemberClass(TypeTagsClass, tpnme.WeakTypeTag) else NoSymbol
- lazy val WeakTypeTagModule = if (TypeTagsClass != NoSymbol) getMemberModule(TypeTagsClass, nme.WeakTypeTag) else NoSymbol
- lazy val TypeTagClass = if (TypeTagsClass != NoSymbol) getMemberClass(TypeTagsClass, tpnme.TypeTag) else NoSymbol
- lazy val TypeTagModule = if (TypeTagsClass != NoSymbol) getMemberModule(TypeTagsClass, nme.TypeTag) else NoSymbol
- def materializeClassTag = getMemberMethod(ReflectPackage, nme.materializeClassTag)
- def materializeWeakTypeTag = if (ReflectApiPackage != NoSymbol) getMemberMethod(ReflectApiPackage, nme.materializeWeakTypeTag) else NoSymbol
- def materializeTypeTag = if (ReflectApiPackage != NoSymbol) getMemberMethod(ReflectApiPackage, nme.materializeTypeTag) else NoSymbol
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 MirrorClass = getClassIfDefined("scala.reflect.api.Mirror") // defined in scala-reflect.jar, so we need to be careful
@@ -527,15 +490,26 @@ trait Definitions extends api.StandardDefinitions {
lazy val TypeCreatorClass = getClassIfDefined("scala.reflect.api.TypeCreator") // defined in scala-reflect.jar, so we need to be careful
lazy val TreeCreatorClass = getClassIfDefined("scala.reflect.api.TreeCreator") // defined in scala-reflect.jar, so we need to be careful
- lazy val MacroContextClass = getClassIfDefined("scala.reflect.macros.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) getTypeMember(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
- lazy val MacroImplAnnotation = requiredClass[scala.reflect.macros.internal.macroImpl]
+ private def Context_210 = if (settings.isScala211) NoSymbol else getClassIfDefined("scala.reflect.macros.Context") // needed under -Xsource:2.10
+ lazy val BlackboxContextClass = getClassIfDefined("scala.reflect.macros.blackbox.Context").orElse(Context_210) // defined in scala-reflect.jar, so we need to be careful
- lazy val StringContextClass = requiredClass[scala.StringContext]
- def StringContext_f = getMemberMethod(StringContextClass, nme.f)
+ lazy val WhiteboxContextClass = getClassIfDefined("scala.reflect.macros.whitebox.Context").orElse(Context_210) // defined in scala-reflect.jar, so we need to be careful
+ def MacroContextPrefix = BlackboxContextClass.map(sym => getMemberMethod(sym, nme.prefix))
+ def MacroContextPrefixType = BlackboxContextClass.map(sym => getTypeMember(sym, tpnme.PrefixType))
+ def MacroContextUniverse = BlackboxContextClass.map(sym => getMemberMethod(sym, nme.universe))
+ def MacroContextExprClass = BlackboxContextClass.map(sym => getTypeMember(sym, tpnme.Expr))
+ def MacroContextWeakTypeTagClass = BlackboxContextClass.map(sym => getTypeMember(sym, tpnme.WeakTypeTag))
+ def MacroContextTreeType = BlackboxContextClass.map(sym => getTypeMember(sym, tpnme.Tree))
+ lazy val MacroImplAnnotation = requiredClass[scala.reflect.macros.internal.macroImpl]
+
+ lazy val StringContextClass = requiredClass[scala.StringContext]
+
+ // SI-8392 a reflection universe on classpath may not have
+ // quasiquotes, if e.g. crosstyping with -Xsource on
+ lazy val QuasiquoteClass = if (ApiUniverseClass != NoSymbol) getMemberIfDefined(ApiUniverseClass, tpnme.Quasiquote) else NoSymbol
+ lazy val QuasiquoteClass_api = if (QuasiquoteClass != NoSymbol) getMember(QuasiquoteClass, tpnme.api) else NoSymbol
+ lazy val QuasiquoteClass_api_apply = if (QuasiquoteClass_api != NoSymbol) getMember(QuasiquoteClass_api, nme.apply) else NoSymbol
+ lazy val QuasiquoteClass_api_unapply = if (QuasiquoteClass_api != NoSymbol) getMember(QuasiquoteClass_api, nme.unapply) else NoSymbol
lazy val ScalaSignatureAnnotation = requiredClass[scala.reflect.ScalaSignature]
lazy val ScalaLongSignatureAnnotation = requiredClass[scala.reflect.ScalaLongSignature]
@@ -543,7 +517,6 @@ trait Definitions extends api.StandardDefinitions {
// Option classes
lazy val OptionClass: ClassSymbol = requiredClass[Option[_]]
lazy val OptionModule: ModuleSymbol = requiredModule[scala.Option.type]
- lazy val Option_apply = getMemberMethod(OptionModule, nme.apply)
lazy val SomeClass: ClassSymbol = requiredClass[Some[_]]
lazy val NoneModule: ModuleSymbol = requiredModule[scala.None.type]
lazy val SomeModule: ModuleSymbol = requiredModule[scala.Some.type]
@@ -551,10 +524,6 @@ trait Definitions extends api.StandardDefinitions {
def compilerTypeFromTag(tt: ApiUniverse # WeakTypeTag[_]): Type = tt.in(rootMirror).tpe
def compilerSymbolFromTag(tt: ApiUniverse # WeakTypeTag[_]): 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
@@ -563,37 +532,33 @@ trait Definitions extends api.StandardDefinitions {
// 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: _*)
+ class VarArityClass(name: String, maxArity: Int, countFrom: Int = 0, init: Option[ClassSymbol] = None) extends VarArityClassApi {
+ private val offset = countFrom - init.size
+ private def isDefinedAt(i: Int) = i < seq.length + offset && i >= offset
+ val seq: IndexedSeq[ClassSymbol] = (init ++: countFrom.to(maxArity).map { i => getRequiredClass("scala." + name + i) }).toVector
+ def apply(i: Int) = if (isDefinedAt(i)) seq(i - offset) else NoSymbol
+ def specificType(args: List[Type], others: Type*): Type = {
+ val arity = args.length
+ if (!isDefinedAt(arity)) NoType
+ else appliedType(apply(arity), args ++ others: _*)
+ }
}
+ // would be created synthetically for the default args. We call all objects in this method from the generated code
+ // in JavaUniverseForce, so it is clearer to define this explicitly define this in source.
+ object VarArityClass
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)
+
+ lazy val ProductClass = new VarArityClass("Product", MaxProductArity, countFrom = 1, init = Some(UnitClass))
+ lazy val TupleClass = new VarArityClass("Tuple", MaxTupleArity, countFrom = 1)
+ lazy val FunctionClass = new VarArityClass("Function", MaxFunctionArity)
+ lazy val AbstractFunctionClass = new VarArityClass("runtime.AbstractFunction", MaxFunctionArity)
/** 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 tupleType(elems: List[Type]) = TupleClass.specificType(elems)
+ def functionType(formals: List[Type], restpe: Type) = FunctionClass.specificType(formals, restpe)
+ def abstractFunctionType(formals: List[Type], restpe: Type) = AbstractFunctionClass.specificType(formals, restpe)
def wrapArrayMethodName(elemtp: Type): TermName = elemtp.typeSymbol match {
case ByteClass => nme.wrapByteArray
@@ -606,17 +571,13 @@ trait Definitions extends api.StandardDefinitions {
case BooleanClass => nme.wrapBooleanArray
case UnitClass => nme.wrapUnitArray
case _ =>
- if ((elemtp <:< AnyRefClass.tpe) && !isPhantomClass(elemtp.typeSymbol)) nme.wrapRefArray
+ if ((elemtp <:< AnyRefTpe) && !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 isTupleSymbol(sym: Symbol) = TupleClass.seq contains unspecializedSymbol(sym)
+ def isFunctionSymbol(sym: Symbol) = FunctionClass.seq contains unspecializedSymbol(sym)
+ def isProductNSymbol(sym: Symbol) = ProductClass.seq contains unspecializedSymbol(sym)
def unspecializedSymbol(sym: Symbol): Symbol = {
if (sym hasFlag SPECIALIZED) {
@@ -627,31 +588,71 @@ trait Definitions extends api.StandardDefinitions {
}
else sym
}
+ def unspecializedTypeArgs(tp: Type): List[Type] =
+ (tp baseType unspecializedSymbol(tp.typeSymbolDirect)).typeArgs
+
+ object MacroContextType {
+ def unapply(tp: Type) = {
+ def isOneOfContextTypes(tp: Type) =
+ tp =:= BlackboxContextClass.tpe || tp =:= WhiteboxContextClass.tpe
+ def isPrefix(sym: Symbol) =
+ sym.allOverriddenSymbols.contains(MacroContextPrefixType)
+
+ tp.dealias match {
+ case RefinedType(List(tp), Scope(sym)) if isOneOfContextTypes(tp) && isPrefix(sym) => Some(tp)
+ case tp if isOneOfContextTypes(tp) => Some(tp)
+ case _ => None
+ }
+ }
+ }
- // 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))
+ def isMacroContextType(tp: Type) = MacroContextType.unapply(tp).isDefined
+
+ def isWhiteboxContextType(tp: Type) =
+ isMacroContextType(tp) && (tp <:< WhiteboxContextClass.tpe)
+
+ private def macroBundleParamInfo(tp: Type) = {
+ val ctor = tp.erasure.typeSymbol.primaryConstructor
+ ctor.paramss match {
+ case List(List(c)) =>
+ val sym = c.info.typeSymbol
+ val isContextCompatible = sym.isNonBottomSubClass(BlackboxContextClass) || sym.isNonBottomSubClass(WhiteboxContextClass)
+ if (isContextCompatible) c.info else NoType
case _ =>
- false
- })
+ NoType
+ }
}
- // 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 looksLikeMacroBundleType(tp: Type) =
+ macroBundleParamInfo(tp) != NoType
+
+ def isMacroBundleType(tp: Type) = {
+ val isMonomorphic = tp.typeSymbol.typeParams.isEmpty
+ val isContextCompatible = isMacroContextType(macroBundleParamInfo(tp))
+ val hasSingleConstructor = !tp.declaration(nme.CONSTRUCTOR).isOverloaded
+ val nonAbstract = !tp.erasure.typeSymbol.isAbstractClass
+ isMonomorphic && isContextCompatible && hasSingleConstructor && nonAbstract
}
- def isTupleType(tp: Type) = isTupleTypeDirect(tp.normalize)
+
+ def isBlackboxMacroBundleType(tp: Type) = {
+ val isBundle = isMacroBundleType(tp)
+ val unwrappedContext = MacroContextType.unapply(macroBundleParamInfo(tp)).getOrElse(NoType)
+ val isBlackbox = unwrappedContext =:= BlackboxContextClass.tpe
+ isBundle && isBlackbox
+ }
+
+ def isListType(tp: Type) = tp <:< classExistentialType(ListClass)
+ def isIterableType(tp: Type) = tp <:< classExistentialType(IterableClass)
+
+ // These "direct" calls perform no dealiasing. They are most needed when
+ // printing types when one wants to preserve the true nature of the type.
+ def isFunctionTypeDirect(tp: Type) = !tp.isHigherKinded && isFunctionSymbol(tp.typeSymbolDirect)
+ def isTupleTypeDirect(tp: Type) = !tp.isHigherKinded && isTupleSymbol(tp.typeSymbolDirect)
+
+ // Note that these call .dealiasWiden and not .normalize, the latter of which
+ // tends to change the course of events by forcing types.
+ def isFunctionType(tp: Type) = isFunctionTypeDirect(tp.dealiasWiden)
+ def isTupleType(tp: Type) = isTupleTypeDirect(tp.dealiasWiden)
lazy val ProductRootClass: ClassSymbol = requiredClass[scala.Product]
def Product_productArity = getMemberMethod(ProductRootClass, nme.productArity)
@@ -659,43 +660,122 @@ trait Definitions extends api.StandardDefinitions {
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 {
+ @deprecated("No longer used", "2.11.0") def getProductArgs(tpe: Type): List[Type] = tpe.baseClasses find isProductNSymbol match {
case Some(x) => tpe.baseType(x).typeArgs
case _ => Nil
}
+ @deprecated("No longer used", "2.11.0") def unapplyUnwrap(tpe:Type) = tpe.finalResultType.dealiasWiden match {
+ case RefinedType(p :: _, _) => p.dealiasWiden
+ case tp => tp
+ }
+
+ def getterMemberTypes(tpe: Type, getters: List[Symbol]): List[Type] =
+ getters map (m => dropNullaryMethod(tpe memberType m))
+
def dropNullaryMethod(tp: Type) = tp match {
case NullaryMethodType(restpe) => restpe
case _ => tp
}
- def unapplyUnwrap(tpe:Type) = tpe.finalResultType.normalize match {
- case RefinedType(p :: _, _) => p.normalize
- case tp => tp
+ /** An implementation of finalResultType which does only what
+ * finalResultType is documented to do. Defining it externally to
+ * Type helps ensure people can't come to depend on accidental
+ * aspects of its behavior. This is all of it!
+ */
+ def finalResultType(tp: Type): Type = tp match {
+ case PolyType(_, restpe) => finalResultType(restpe)
+ case MethodType(_, restpe) => finalResultType(restpe)
+ case NullaryMethodType(restpe) => finalResultType(restpe)
+ case _ => tp
+ }
+ /** Similarly, putting all the isStable logic in one place.
+ * This makes it like 1000x easier to see the overall logic
+ * of the method.
+ */
+ def isStable(tp: Type): Boolean = tp match {
+ case _: SingletonType => true
+ case NoPrefix => true
+ case TypeRef(_, NothingClass | SingletonClass, _) => true
+ case TypeRef(_, sym, _) if sym.isAbstractType => tp.bounds.hi.typeSymbol isSubClass SingletonClass
+ case TypeRef(pre, sym, _) if sym.isModuleClass => isStable(pre)
+ case TypeRef(_, _, _) if tp ne tp.dealias => isStable(tp.dealias)
+ case TypeVar(origin, _) => isStable(origin)
+ case AnnotatedType(_, atp) => isStable(atp) // Really?
+ case _: SimpleTypeProxy => isStable(tp.underlying)
+ case _ => false
}
+ def isVolatile(tp: Type): Boolean = {
+ // 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
+ def isVolatileAbstractType: Boolean = {
+ def sym = tp.typeSymbol
+ def volatileUpperBound = isVolatile(tp.bounds.hi)
+ def safeIsVolatile = (
+ if (volatileRecursions < TypeConstants.LogVolatileThreshold)
+ volatileUpperBound
+ // we can return true when pendingVolatiles contains sym, because
+ // a cycle will be detected afterwards and an error will result anyway.
+ else pendingVolatiles(sym) || {
+ pendingVolatiles += sym
+ try volatileUpperBound finally pendingVolatiles -= sym
+ }
+ )
+ volatileRecursions += 1
+ try safeIsVolatile finally volatileRecursions -= 1
+ }
+ /** 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.
+ */
+ def isVolatileRefinedType: Boolean = {
+ val RefinedType(parents, decls) = tp
+ def isVisibleDeferred(m: Symbol) = m.isDeferred && ((tp nonPrivateMember m.name).alternatives contains m)
+ def contributesAbstractMembers(p: Type) = p.deferredMembers exists isVisibleDeferred
+ def dropConcreteParents = parents dropWhile (p => !p.typeSymbol.isAbstractType)
+
+ (parents exists isVolatile) || {
+ dropConcreteParents match {
+ case Nil => false
+ case ps => (ps ne parents) || (ps.tail exists contributesAbstractMembers) || (decls exists isVisibleDeferred)
+ }
+ }
+ }
- def functionApply(n: Int) = getMemberMethod(FunctionClass(n), nme.apply)
+ tp match {
+ case ThisType(_) => false
+ case SingleType(_, sym) => isVolatile(tp.underlying) && (sym.hasVolatileType || !sym.isStable)
+ case NullaryMethodType(restpe) => isVolatile(restpe)
+ case PolyType(_, restpe) => isVolatile(restpe)
+ case TypeRef(_, _, _) if tp ne tp.dealias => isVolatile(tp.dealias)
+ case TypeRef(_, sym, _) if sym.isAbstractType => isVolatileAbstractType
+ case RefinedType(_, _) => isVolatileRefinedType
+ case TypeVar(origin, _) => isVolatile(origin)
+ case _: SimpleTypeProxy => isVolatile(tp.underlying)
+ case _ => false
+ }
+ }
+ private[this] var volatileRecursions: Int = 0
+ private[this] val pendingVolatiles = mutable.HashSet[Symbol]()
def abstractFunctionForFunctionType(tp: Type) = {
assert(isFunctionType(tp), tp)
abstractFunctionType(tp.typeArgs.init, tp.typeArgs.last)
}
-
- 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 functionNBaseType(tp: Type): Type = tp.baseClasses find isFunctionSymbol match {
+ case Some(sym) => tp baseType unspecializedSymbol(sym)
+ case _ => tp
}
def isPartialFunctionType(tp: Type): Boolean = {
@@ -703,11 +783,42 @@ trait Definitions extends api.StandardDefinitions {
(sym eq PartialFunctionClass) || (sym eq AbstractPartialFunctionClass)
}
- def isSeqType(tp: Type) = elementType(SeqClass, tp.normalize) != NoType
+ /** The single abstract method declared by type `tp` (or `NoSymbol` if it cannot be found).
+ *
+ * The method must be monomorphic and have exactly one parameter list.
+ * The class defining the method is a supertype of `tp` that
+ * has a public no-arg primary constructor.
+ */
+ def samOf(tp: Type): Symbol = {
+ // if tp has a constructor, it must be public and must not take any arguments
+ // (not even an implicit argument list -- to keep it simple for now)
+ val tpSym = tp.typeSymbol
+ val ctor = tpSym.primaryConstructor
+ val ctorOk = !ctor.exists || (!ctor.isOverloaded && ctor.isPublic && ctor.info.params.isEmpty && ctor.info.paramSectionCount <= 1)
+
+ if (tpSym.exists && ctorOk) {
+ // find the single abstract member, if there is one
+ // don't go out requiring DEFERRED members, as you will get them even if there's a concrete override:
+ // scala> abstract class X { def m: Int }
+ // scala> class Y extends X { def m: Int = 1}
+ // scala> typeOf[Y].deferredMembers
+ // Scopes(method m, method getClass)
+ //
+ // scala> typeOf[Y].members.filter(_.isDeferred)
+ // Scopes()
+ // must filter out "universal" members (getClass is deferred for some reason)
+ val deferredMembers = (
+ tp membersBasedOnFlags (excludedFlags = BridgeAndPrivateFlags, requiredFlags = METHOD)
+ filter (mem => mem.isDeferredNotDefault && !isUniversalMember(mem)) // TODO: test
+ )
- def elementType(container: Symbol, tp: Type): Type = tp match {
- case TypeRef(_, `container`, arg :: Nil) => arg
- case _ => NoType
+ // if there is only one, it's monomorphic and has a single argument list
+ if (deferredMembers.size == 1 &&
+ deferredMembers.head.typeParams.isEmpty &&
+ deferredMembers.head.info.paramSectionCount == 1)
+ deferredMembers.head
+ else NoSymbol
+ } else NoSymbol
}
def arrayType(arg: Type) = appliedType(ArrayClass, arg)
@@ -717,14 +828,75 @@ trait Definitions extends api.StandardDefinitions {
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)
+ // FYI the long clunky name is because it's really hard to put "get" into the
+ // name of a method without it sounding like the method "get"s something, whereas
+ // this method is about a type member which just happens to be named get.
+ def typeOfMemberNamedGet(tp: Type) = typeArgOfBaseTypeOr(tp, OptionClass)(resultOfMatchingMethod(tp, nme.get)())
+ def typeOfMemberNamedHead(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.head)())
+ def typeOfMemberNamedApply(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.apply)(IntTpe))
+ def typeOfMemberNamedDrop(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.drop)(IntTpe))
+ def typesOfSelectors(tp: Type) = getterMemberTypes(tp, productSelectors(tp))
+ // SI-8128 Still using the type argument of the base type at Seq/Option if this is an old-style (2.10 compatible)
+ // extractor to limit exposure to regressions like the reported problem with existentials.
+ // TODO fix the existential problem in the general case, see test/pending/pos/t8128.scala
+ private def typeArgOfBaseTypeOr(tp: Type, baseClass: Symbol)(or: => Type): Type = (tp baseType baseClass).typeArgs match {
+ case x :: Nil => x
+ case _ => or
+ }
- def ClassType(arg: Type) =
- if (phase.erasedTypes || forMSIL) ClassClass.tpe
- else appliedType(ClassClass, arg)
+ // Can't only check for _1 thanks to pos/t796.
+ def hasSelectors(tp: Type) = (
+ (tp.members containsName nme._1)
+ && (tp.members containsName nme._2)
+ )
+
+ /** Returns the method symbols for members _1, _2, ..., _N
+ * which exist in the given type.
+ */
+ def productSelectors(tpe: Type): List[Symbol] = {
+ def loop(n: Int): List[Symbol] = tpe member TermName("_" + n) match {
+ case NoSymbol => Nil
+ case m if m.paramss.nonEmpty => Nil
+ case m => m :: loop(n + 1)
+ }
+ // Since ErrorType always returns a symbol from a call to member, we
+ // had better not start looking for _1, _2, etc. expecting it to run out.
+ if (tpe.isErroneous) Nil else loop(1)
+ }
+
+ /** If `tp` has a term member `name`, the first parameter list of which
+ * matches `paramTypes`, and which either has no further parameter
+ * lists or only an implicit one, then the result type of the matching
+ * method. Otherwise, NoType.
+ */
+ def resultOfMatchingMethod(tp: Type, name: TermName)(paramTypes: Type*): Type = {
+ def matchesParams(member: Symbol) = member.paramss match {
+ case Nil => paramTypes.isEmpty
+ case ps :: rest => (rest.isEmpty || isImplicitParamss(rest)) && (ps corresponds paramTypes)(_.tpe =:= _)
+ }
+ tp member name filter matchesParams match {
+ case NoSymbol => NoType
+ case member => (tp memberType member).finalResultType
+ }
+ }
+
+ def ClassType(arg: Type) = if (phase.erasedTypes) ClassClass.tpe else appliedType(ClassClass, arg)
+
+ /** Can we tell by inspecting the symbol that it will never
+ * at any phase have type parameters?
+ */
+ def neverHasTypeParameters(sym: Symbol) = sym match {
+ case _: RefinementClassSymbol => true
+ case _: ModuleClassSymbol => true
+ case _: ImplClassSymbol => true
+ case _ =>
+ (
+ sym.isPrimitiveValueClass
+ || sym.isAnonymousClass
+ || sym.initialize.isMonomorphicType
+ )
+ }
def EnumType(sym: Symbol) =
// given (in java): "class A { enum E { VAL1 } }"
@@ -733,66 +905,34 @@ trait Definitions extends api.StandardDefinitions {
// - .linkedClassOfClass: the ClassSymbol of the enumeration (class E)
sym.owner.linkedClassOfClass.tpe
- 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 }.
*/
+ // TODO Review the way this is used. I see two potential problems:
+ // 1. `existentialAbstraction` here doesn't create fresh existential type symbols, it just
+ // uses the class type parameter symbols directly as the list of quantified symbols.
+ // See SI-8244 for the trouble that this can cause.
+ // Compare with callers of `typeParamsToExistentials` (used in Java raw type handling)
+ // 2. Why don't we require a prefix? Could its omission lead to wrong results in CheckabilityChecker?
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)
+ existentialAbstraction(clazz.typeParams, clazz.tpe_*)
- //
- // .NET backend
- //
+ // members of class scala.Any
- 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
- })
- }
+ // TODO these aren't final! They are now overriden in AnyRef/Object. Prior to the fix
+ // for SI-8129, they were actually *overloaded* by the members in AnyRef/Object.
+ // We should unfinalize these, override in AnyValClass, and make the overrides final.
+ // Refchecks never actually looks at these, so its just for consistency.
+ lazy val Any_== = enterNewMethod(AnyClass, nme.EQ, AnyTpe :: Nil, BooleanTpe, FINAL)
+ lazy val Any_!= = enterNewMethod(AnyClass, nme.NE, AnyTpe :: Nil, BooleanTpe, FINAL)
- // 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)
+ lazy val Any_equals = enterNewMethod(AnyClass, nme.equals_, AnyTpe :: Nil, BooleanTpe)
+ lazy val Any_hashCode = enterNewMethod(AnyClass, nme.hashCode_, Nil, IntTpe)
+ lazy val Any_toString = enterNewMethod(AnyClass, nme.toString_, Nil, StringTpe)
+ lazy val Any_## = enterNewMethod(AnyClass, nme.HASHHASH, Nil, IntTpe, 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:
@@ -804,7 +944,7 @@ trait Definitions extends api.StandardDefinitions {
// 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_isInstanceOf = newT1NullaryMethod(AnyClass, nme.isInstanceOf_, FINAL)(_ => BooleanTpe)
lazy val Any_asInstanceOf = newT1NullaryMethod(AnyClass, nme.asInstanceOf_, FINAL)(_.typeConstructor)
lazy val primitiveGetClassMethods = Set[Symbol](Any_getClass, AnyVal_getClass) ++ (
@@ -834,7 +974,7 @@ trait Definitions extends api.StandardDefinitions {
else {
val eparams = typeParamsToExistentials(ClassClass, ClassClass.typeParams)
val upperBound = (
- if (isPhantomClass(sym)) AnyClass.tpe
+ if (isPhantomClass(sym)) AnyTpe
else if (sym.isLocalClass) erasure.intersectionDominator(tp.parents)
else tp.widen
)
@@ -860,12 +1000,7 @@ trait Definitions extends api.StandardDefinitions {
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
@@ -893,27 +1028,23 @@ trait Definitions extends api.StandardDefinitions {
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_## = enterNewMethod(ObjectClass, nme.HASHHASH, Nil, IntTpe, FINAL)
+ lazy val Object_== = enterNewMethod(ObjectClass, nme.EQ, AnyTpe :: Nil, BooleanTpe, FINAL)
+ lazy val Object_!= = enterNewMethod(ObjectClass, nme.NE, AnyTpe :: Nil, BooleanTpe, FINAL)
+ lazy val Object_eq = enterNewMethod(ObjectClass, nme.eq, AnyRefTpe :: Nil, BooleanTpe, FINAL)
+ lazy val Object_ne = enterNewMethod(ObjectClass, nme.ne, AnyRefTpe :: Nil, BooleanTpe, FINAL)
+ lazy val Object_isInstanceOf = newT1NoParamsMethod(ObjectClass, nme.isInstanceOf_Ob, FINAL | SYNTHETIC | ARTIFACT)(_ => BooleanTpe)
+ lazy val Object_asInstanceOf = newT1NoParamsMethod(ObjectClass, nme.asInstanceOf_Ob, FINAL | SYNTHETIC | ARTIFACT)(_.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)
+ lazy val String_+ = enterNewMethod(StringClass, nme.raw.PLUS, AnyTpe :: Nil, StringTpe, FINAL)
def Object_getClass = getMemberMethod(ObjectClass, nme.getClass_)
def Object_clone = getMemberMethod(ObjectClass, nme.clone_)
@@ -940,9 +1071,6 @@ trait Definitions extends api.StandardDefinitions {
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)
@@ -959,7 +1087,6 @@ trait Definitions extends api.StandardDefinitions {
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]
@@ -968,8 +1095,7 @@ trait Definitions extends api.StandardDefinitions {
lazy val BeanPropertyAttr = requiredClass[scala.beans.BeanProperty]
lazy val BooleanBeanPropertyAttr = requiredClass[scala.beans.BooleanBeanProperty]
- lazy val CloneableAttr = requiredClass[scala.annotation.cloneable]
- lazy val CompileTimeOnlyAttr = getClassIfDefined("scala.reflect.internal.annotations.compileTimeOnly")
+ lazy val CompileTimeOnlyAttr = getClassIfDefined("scala.annotation.compileTimeOnly")
lazy val DeprecatedAttr = requiredClass[scala.deprecated]
lazy val DeprecatedNameAttr = requiredClass[scala.deprecatedName]
lazy val DeprecatedInheritanceAttr = requiredClass[scala.deprecatedInheritance]
@@ -979,6 +1105,7 @@ trait Definitions extends api.StandardDefinitions {
lazy val ScalaInlineClass = requiredClass[scala.inline]
lazy val ScalaNoInlineClass = requiredClass[scala.noinline]
lazy val SerialVersionUIDAttr = requiredClass[scala.SerialVersionUID]
+ lazy val SerialVersionUIDAnnotation = AnnotationInfo(SerialVersionUIDAttr.tpe, List(Literal(Constant(0))), List())
lazy val SpecializedClass = requiredClass[scala.specialized]
lazy val ThrowsClass = requiredClass[scala.throws[_]]
lazy val TransientAttr = requiredClass[scala.transient]
@@ -994,53 +1121,56 @@ trait Definitions extends api.StandardDefinitions {
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 ClassTargetClass = requiredClass[meta.companionClass]
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 metaAnnotations: Set[Symbol] = getPackage("scala.annotation.meta").info.members filter (_ isSubClass StaticAnnotationClass) toSet
+
+ // According to the scala.annotation.meta package object:
+ // * By default, annotations on (`val`-, `var`- or plain) constructor parameters
+ // * end up on the parameter, not on any other entity. Annotations on fields
+ // * by default only end up on the field.
+ def defaultAnnotationTarget(t: Tree): Symbol = t match {
+ case ClassDef(_, _, _, _) => ClassTargetClass
+ case ModuleDef(_, _, _) => ObjectTargetClass
+ case vd @ ValDef(_, _, _, _) if vd.symbol.isParamAccessor => ParamTargetClass
+ case vd @ ValDef(_, _, _, _) if vd.symbol.isValueParameter => ParamTargetClass
+ case ValDef(_, _, _, _) => FieldTargetClass
+ case DefDef(_, _, _, _, _, _) => MethodTargetClass
+ case _ => GetterTargetClass
+ }
lazy val AnnotationDefaultAttr: ClassSymbol = {
- val attr = enterNewClass(RuntimePackageClass, tpnme.AnnotationDefaultATTR, List(AnnotationClass.tpe))
- // This attribute needs a constructor so that modifiers in parsed Java code make sense
- attr.info.decls enter attr.newClassConstructor(NoPosition)
- attr
+ val sym = RuntimePackageClass.newClassSymbol(tpnme.AnnotationDefaultATTR, NoPosition, 0L)
+ sym setInfo ClassInfoType(List(AnnotationClass.tpe), newScope, sym)
+ markAllCompleted(sym)
+ RuntimePackageClass.info.decls.toList.filter(_.name == sym.name) match {
+ case existing :: _ =>
+ existing.asInstanceOf[ClassSymbol]
+ case _ =>
+ RuntimePackageClass.info.decls enter sym
+ // This attribute needs a constructor so that modifiers in parsed Java code make sense
+ sym.info.decls enter sym.newClassConstructor(NoPosition)
+ sym
+ }
}
- @deprecated("Moved to rootMirror.getClass", "2.10.0")
- def getClass(fullname: Name): ClassSymbol = rootMirror.getClassByName(fullname)
-
- @deprecated("Moved to rootMirror.getModule", "2.10.0")
- def getModule(fullname: Name): ModuleSymbol = rootMirror.getModule(fullname)
-
- private def fatalMissingSymbol(owner: Symbol, name: Name, what: String = "member") = {
- throw new FatalError(owner + " does not have a " + what + " " + name)
+ private def fatalMissingSymbol(owner: Symbol, name: Name, what: String = "member", addendum: String = "") = {
+ throw new FatalError(owner + " does not have a " + what + " " + name + addendum)
}
def getLanguageFeature(name: String, owner: Symbol = languageFeatureModule): Symbol = getMember(owner, newTypeName(name))
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)
@@ -1070,7 +1200,8 @@ trait Definitions extends api.StandardDefinitions {
def getMemberModule(owner: Symbol, name: Name): ModuleSymbol = {
getMember(owner, name.toTermName) match {
case x: ModuleSymbol => x
- case _ => fatalMissingSymbol(owner, name, "member object")
+ case NoSymbol => fatalMissingSymbol(owner, name, "member object")
+ case other => fatalMissingSymbol(owner, name, "member object", addendum = s". A symbol ${other} of kind ${other.accurateKindString} already exists.")
}
}
def getTypeMember(owner: Symbol, name: Name): TypeSymbol = {
@@ -1080,7 +1211,6 @@ trait Definitions extends api.StandardDefinitions {
}
}
def getMemberClass(owner: Symbol, name: Name): ClassSymbol = {
- val y = getMember(owner, name.toTypeName)
getMember(owner, name.toTypeName) match {
case x: ClassSymbol => x
case _ => fatalMissingSymbol(owner, name, "member class")
@@ -1088,15 +1218,21 @@ trait Definitions extends api.StandardDefinitions {
}
def getMemberMethod(owner: Symbol, name: Name): TermSymbol = {
getMember(owner, name.toTermName) match {
- // todo. member symbol becomes a term symbol in cleanup. is this a bug?
- // case x: MethodSymbol => x
case x: TermSymbol => x
case _ => fatalMissingSymbol(owner, name, "method")
}
}
+ private lazy val erasurePhase = findPhaseWithName("erasure")
def getMemberIfDefined(owner: Symbol, name: Name): Symbol =
- owner.info.nonPrivateMember(name)
+ // findMember considered harmful after erasure; e.g.
+ //
+ // scala> exitingErasure(Symbol_apply).isOverloaded
+ // res27: Boolean = true
+ //
+ enteringPhaseNotLaterThan(erasurePhase )(
+ owner.info.nonPrivateMember(name)
+ )
/** Using getDecl rather than getMember may avoid issues with
* OverloadedTypes turning up when you don't want them, if you
@@ -1108,18 +1244,15 @@ trait Definitions extends api.StandardDefinitions {
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))
+ val parents = List(AnyRefTpe, parentFn(tparam))
- clazz setInfo GenPolyType(List(tparam), ClassInfoType(parents, newScope, clazz))
+ clazz setInfo GenPolyType(List(tparam), ClassInfoType(parents, newScope, clazz)) markAllCompleted
}
def newPolyMethod(typeParamCount: Int, owner: Symbol, name: TermName, flags: Long)(createFn: PolyMethodCreator): MethodSymbol = {
@@ -1130,7 +1263,7 @@ trait Definitions extends api.StandardDefinitions {
case (_, restpe) => NullaryMethodType(restpe)
}
- msym setInfoAndEnter genPolyType(tparams, mtpe)
+ msym setInfoAndEnter genPolyType(tparams, mtpe) markAllCompleted
}
/** T1 means one type parameter.
@@ -1142,10 +1275,6 @@ trait Definitions extends api.StandardDefinitions {
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)
/** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
@@ -1159,8 +1288,7 @@ trait Definitions extends api.StandardDefinitions {
AnyValClass,
NullClass,
NothingClass,
- SingletonClass,
- EqualsPatternClass
+ SingletonClass
)
/** Lists core methods that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
lazy val syntheticCoreMethods = List(
@@ -1196,14 +1324,12 @@ trait Definitions extends api.StandardDefinitions {
lazy val symbolsNotPresentInBytecode = syntheticCoreClasses ++ syntheticCoreMethods ++ hijackedCoreClasses
/** Is the symbol that of a parent which is added during parsing? */
- lazy val isPossibleSyntheticParent = ProductClass.toSet[Symbol] + ProductRootClass + SerializableClass
+ lazy val isPossibleSyntheticParent = ProductClass.seq.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? */
@@ -1220,7 +1346,7 @@ trait Definitions extends api.StandardDefinitions {
/** Is type's symbol a numeric value class? */
def isNumericValueType(tp: Type): Boolean = tp match {
case TypeRef(_, sym, _) => isNumericValueClass(sym)
- case _ => false
+ case _ => false
}
// todo: reconcile with javaSignature!!!
@@ -1232,10 +1358,10 @@ trait Definitions extends api.StandardDefinitions {
}
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 if (sym.isTopLevel) 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))
+ if (etp.typeSymbol == ArrayClass) "[" + signature1(erasure(etp.dealiasWiden.typeArgs.head))
else if (isPrimitiveValueClass(etp.typeSymbol)) abbrvTag(etp.typeSymbol).toString()
else "L" + flatNameString(etp.typeSymbol, '/') + ";"
}
@@ -1244,49 +1370,127 @@ trait Definitions extends api.StandardDefinitions {
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
- }
-
+ // documented in JavaUniverse.init
def init() {
if (isInitialized) return
- // force initialization of every symbol that is synthesized or hijacked by the compiler
- val forced = symbolsNotPresentInBytecode
+ ObjectClass.initialize
+ ScalaPackageClass.initialize
+ val forced1 = symbolsNotPresentInBytecode
+ val forced2 = NoSymbol
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
+ class UniverseDependentTypes(universe: Tree) {
+ lazy val nameType = universeMemberType(tpnme.Name)
+ lazy val modsType = universeMemberType(tpnme.Modifiers)
+ lazy val flagsType = universeMemberType(tpnme.FlagSet)
+ lazy val symbolType = universeMemberType(tpnme.Symbol)
+ lazy val treeType = universeMemberType(tpnme.Tree)
+ lazy val caseDefType = universeMemberType(tpnme.CaseDef)
+ lazy val liftableType = universeMemberType(tpnme.Liftable)
+ lazy val unliftableType = universeMemberType(tpnme.Unliftable)
+ lazy val iterableTreeType = appliedType(IterableClass, treeType)
+ lazy val listTreeType = appliedType(ListClass, treeType)
+ lazy val listListTreeType = appliedType(ListClass, listTreeType)
+
+ def universeMemberType(name: TypeName) = universe.tpe.memberType(getTypeMember(universe.symbol, name))
}
- // def addScalaCallerInfo(scalaCaller: Symbol, methSym: Symbol, delType: Type) {
- // assert(Delegate_scalaCallers contains scalaCaller)
- // Delegate_scalaCallerInfos += (scalaCaller -> (methSym, delType))
- // }
+ /** Efficient access to member symbols which must be looked up each run. Access via `currentRun.runDefinitions` */
+ final class RunDefinitions {
+ lazy val StringAdd_+ = getMemberMethod(StringAddClass, nme.PLUS)
+
+ // The given symbol represents either String.+ or StringAdd.+
+ def isStringAddition(sym: Symbol) = sym == String_+ || sym == StringAdd_+
+
+ lazy val StringContext_f = getMemberMethod(StringContextClass, nme.f)
+
+ lazy val ArrowAssocClass = getMemberClass(PredefModule, TypeName("ArrowAssoc")) // SI-5731
+ def isArrowAssoc(sym: Symbol) = sym.owner == ArrowAssocClass
+
+ lazy val Boxes_isNumberOrBool = getDecl(BoxesRunTimeClass, nme.isBoxedNumberOrBoolean)
+ lazy val Boxes_isNumber = getDecl(BoxesRunTimeClass, nme.isBoxedNumber)
- def addScalaCallerInfo(scalaCaller: Symbol, methSym: Symbol) {
- assert(Delegate_scalaCallers contains scalaCaller)
- Delegate_scalaCallerTargets += (scalaCaller -> methSym)
+ 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)
+
+ lazy val boxMethod = classesMap(x => valueCompanionMember(x, nme.box))
+ lazy val unboxMethod = classesMap(x => valueCompanionMember(x, nme.unbox))
+ lazy val isUnbox = unboxMethod.values.toSet[Symbol]
+ lazy val isBox = boxMethod.values.toSet[Symbol]
+
+ lazy val Option_apply = getMemberMethod(OptionModule, nme.apply)
+ lazy val List_apply = DefinitionsClass.this.List_apply
+
+ /**
+ * Is the given symbol `List.apply`?
+ * To to avoid bootstrapping cycles, this return false if the given symbol or List itself is not initialized.
+ */
+ def isListApply(sym: Symbol) = sym.isInitialized && ListModule.hasCompleteInfo && sym == List_apply
+ def isPredefClassOf(sym: Symbol) = if (PredefModule.hasCompleteInfo) sym == Predef_classOf else isPredefMemberNamed(sym, nme.classOf)
+
+ lazy val TagMaterializers = Map[Symbol, Symbol](
+ ClassTagClass -> materializeClassTag,
+ WeakTypeTagClass -> materializeWeakTypeTag,
+ TypeTagClass -> materializeTypeTag
+ )
+ lazy val TagSymbols = TagMaterializers.keySet
+ lazy val Predef_conforms = (getMemberIfDefined(PredefModule, nme.conforms)
+ orElse getMemberMethod(PredefModule, "conforms": TermName)) // TODO: predicate on -Xsource:2.10 (for now, needed for transition from M8 -> RC1)
+ lazy val Predef_classOf = getMemberMethod(PredefModule, nme.classOf)
+ lazy val Predef_implicitly = getMemberMethod(PredefModule, nme.implicitly)
+ lazy val Predef_wrapRefArray = getMemberMethod(PredefModule, nme.wrapRefArray)
+ lazy val Predef_??? = DefinitionsClass.this.Predef_???
+
+ lazy val arrayApplyMethod = getMemberMethod(ScalaRunTimeModule, nme.array_apply)
+ lazy val arrayUpdateMethod = getMemberMethod(ScalaRunTimeModule, nme.array_update)
+ lazy val arrayLengthMethod = getMemberMethod(ScalaRunTimeModule, nme.array_length)
+ lazy val arrayCloneMethod = getMemberMethod(ScalaRunTimeModule, nme.array_clone)
+ lazy val ensureAccessibleMethod = getMemberMethod(ScalaRunTimeModule, nme.ensureAccessible)
+ lazy val arrayClassMethod = getMemberMethod(ScalaRunTimeModule, nme.arrayClass)
+ lazy val traversableDropMethod = getMemberMethod(ScalaRunTimeModule, nme.drop)
+
+ lazy val GroupOfSpecializable = getMemberClass(SpecializableModule, tpnme.Group)
+
+ lazy val WeakTypeTagClass = TypeTagsClass.map(sym => getMemberClass(sym, tpnme.WeakTypeTag))
+ lazy val WeakTypeTagModule = TypeTagsClass.map(sym => getMemberModule(sym, nme.WeakTypeTag))
+ lazy val TypeTagClass = TypeTagsClass.map(sym => getMemberClass(sym, tpnme.TypeTag))
+ lazy val TypeTagModule = TypeTagsClass.map(sym => getMemberModule(sym, nme.TypeTag))
+ lazy val MacroContextUniverse = DefinitionsClass.this.MacroContextUniverse
+
+ lazy val materializeClassTag = getMemberMethod(ReflectPackage, nme.materializeClassTag)
+ lazy val materializeWeakTypeTag = ReflectApiPackage.map(sym => getMemberMethod(sym, nme.materializeWeakTypeTag))
+ lazy val materializeTypeTag = ReflectApiPackage.map(sym => getMemberMethod(sym, nme.materializeTypeTag))
+
+ 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")
+
+ lazy val ApiUniverseReify = ApiUniverseClass.map(sym => getMemberMethod(sym, nme.reify))
+
+ lazy val ReflectRuntimeUniverse = DefinitionsClass.this.ReflectRuntimeUniverse
+ lazy val ReflectRuntimeCurrentMirror = DefinitionsClass.this.ReflectRuntimeCurrentMirror
+
+ lazy val TreesTreeType = TreesClass.map(sym => getTypeMember(sym, tpnme.Tree))
+ object TreeType { def unapply(tpe: Type): Boolean = tpe.typeSymbol.overrideChain contains TreesTreeType }
+ object SubtreeType { def unapply(tpe: Type): Boolean = tpe.typeSymbol.overrideChain exists (_.tpe <:< TreesTreeType.tpe) }
+
+ object ExprClassOf { def unapply(tp: Type): Option[Type] = elementExtractOption(ExprClass, tp) }
+
+ lazy val PartialManifestClass = getTypeMember(ReflectPackage, tpnme.ClassManifest)
+ lazy val ManifestSymbols = Set[Symbol](PartialManifestClass, FullManifestClass, OptManifestClass)
}
}
}
diff --git a/src/reflect/scala/reflect/internal/Depth.scala b/src/reflect/scala/reflect/internal/Depth.scala
new file mode 100644
index 0000000000..357abf765f
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Depth.scala
@@ -0,0 +1,28 @@
+package scala
+package reflect
+package internal
+
+import Depth._
+
+final class Depth private (val depth: Int) extends AnyVal with Ordered[Depth] {
+ def max(that: Depth): Depth = if (this < that) that else this
+ def decr(n: Int): Depth = if (isAnyDepth) this else Depth(depth - n)
+ def incr(n: Int): Depth = if (isAnyDepth) this else Depth(depth + n)
+ def decr: Depth = decr(1)
+ def incr: Depth = incr(1)
+
+ def isNegative = depth < 0
+ def isZero = depth == 0
+ def isAnyDepth = this == AnyDepth
+
+ def compare(that: Depth): Int = if (depth < that.depth) -1 else if (this == that) 0 else 1
+ override def toString = s"Depth($depth)"
+}
+
+object Depth {
+ // A don't care value for the depth parameter in lubs/glbs and related operations.
+ final val AnyDepth = new Depth(Int.MinValue)
+ final val Zero = new Depth(0)
+
+ @inline final def apply(depth: Int): Depth = if (depth < 0) AnyDepth else new Depth(depth)
+}
diff --git a/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala b/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala
index 2c2ed351c9..0eeca4aace 100644
--- a/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala
+++ b/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala
@@ -3,11 +3,11 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package 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.
@@ -84,14 +84,14 @@ trait ExistentialsAndSkolems {
* also replaced, except for term symbols of an Ident tree, where
* only the type of the Ident is changed.
*/
- final def existentialTransform[T](rawSyms: List[Symbol], tp: Type, rawOwner: Option[Symbol] = None)(creator: (List[Symbol], Type) => T): T = {
+ final def existentialTransform[T](rawSyms: List[Symbol], tp: Type, rawOwner: Symbol = NoSymbol)(creator: (List[Symbol], Type) => T): T = {
val allBounds = existentialBoundsExcludingHidden(rawSyms)
val typeParams: List[Symbol] = rawSyms map { sym =>
val name = sym.name match {
case x: TypeName => x
case x => tpnme.singletonName(x)
}
- def rawOwner0 = rawOwner.getOrElse(abort(s"no owner provided for existential transform over raw parameter: $sym"))
+ def rawOwner0 = rawOwner orElse abort(s"no owner provided for existential transform over raw parameter: $sym")
val bound = allBounds(sym)
val sowner = if (isRawParameter(sym)) rawOwner0 else sym.owner
val quantified = sowner.newExistential(name, sym.pos)
@@ -113,7 +113,7 @@ trait ExistentialsAndSkolems {
* @param hidden The original type
* @param rawOwner The owner for Java raw types.
*/
- final def packSymbols(hidden: List[Symbol], tp: Type, rawOwner: Option[Symbol] = None): Type =
+ final def packSymbols(hidden: List[Symbol], tp: Type, rawOwner: Symbol = NoSymbol): Type =
if (hidden.isEmpty) tp
else existentialTransform(hidden, tp, rawOwner)(existentialAbstraction)
}
diff --git a/src/reflect/scala/reflect/internal/FatalError.scala b/src/reflect/scala/reflect/internal/FatalError.scala
index a084fc24f3..08a9a635af 100644
--- a/src/reflect/scala/reflect/internal/FatalError.scala
+++ b/src/reflect/scala/reflect/internal/FatalError.scala
@@ -2,5 +2,6 @@
* Copyright 2005-2013 LAMP/EPFL
* @author Martin Odersky
*/
-package scala.reflect.internal
+package scala
+package 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
index 6a3b6870a0..ef9c77878f 100644
--- a/src/reflect/scala/reflect/internal/FlagSets.scala
+++ b/src/reflect/scala/reflect/internal/FlagSets.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package internal
import scala.language.implicitConversions
@@ -41,5 +42,11 @@ trait FlagSets extends api.FlagSets { self: SymbolTable =>
val DEFAULTPARAM : FlagSet = Flags.DEFAULTPARAM
val PRESUPER : FlagSet = Flags.PRESUPER
val DEFAULTINIT : FlagSet = Flags.DEFAULTINIT
+ val ENUM : FlagSet = Flags.ENUM
+ val PARAMACCESSOR : FlagSet = Flags.PARAMACCESSOR
+ val CASEACCESSOR : FlagSet = Flags.CASEACCESSOR
+ val SYNTHETIC : FlagSet = Flags.SYNTHETIC
+ val ARTIFACT : FlagSet = Flags.ARTIFACT
+ val STABLE : FlagSet = Flags.STABLE
}
}
diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala
index 5ebe02d95d..1707061817 100644
--- a/src/reflect/scala/reflect/internal/Flags.scala
+++ b/src/reflect/scala/reflect/internal/Flags.scala
@@ -3,7 +3,8 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
import scala.collection.{ mutable, immutable }
@@ -62,7 +63,7 @@ import scala.collection.{ mutable, immutable }
// 45: SYNCHRONIZED/M
// 46: ARTIFACT
// 47: DEFAULTMETHOD/M
-// 48:
+// 48: ENUM
// 49:
// 50:
// 51: lateDEFERRED
@@ -116,8 +117,10 @@ class ModifierFlags {
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
- // ARTIFACT at #46 in 2.11+
+ final val ARTIFACT = 1L << 46 // symbol should be ignored when typechecking; will be marked ACC_SYNTHETIC in bytecode
+ // to see which symbols are marked as ARTIFACT, see scaladocs for FlagValues.ARTIFACT
final val DEFAULTMETHOD = 1L << 47 // symbol is a java default method
+ final val ENUM = 1L << 48 // symbol is an enum
// Overridden.
def flagToString(flag: Long): String = ""
@@ -128,7 +131,7 @@ class ModifierFlags {
}
object ModifierFlags extends ModifierFlags
-/** All flags and associated operatins */
+/** All flags and associated operations */
class Flags extends ModifierFlags {
final val METHOD = 1 << 6 // a method
final val MODULE = 1 << 8 // symbol is module or class implementing a module
@@ -163,11 +166,10 @@ class Flags extends ModifierFlags {
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 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
- final val ARTIFACT = 1L << 46 // symbol should be ignored when typechecking; will be marked ACC_SYNTHETIC in bytecode
// ------- shift definitions -------------------------------------------------------
@@ -250,7 +252,7 @@ class Flags extends ModifierFlags {
/** These modifiers appear in TreePrinter output. */
final val PrintableFlags =
ExplicitFlags | BridgeFlags | LOCAL | SYNTHETIC | STABLE | CASEACCESSOR | MACRO |
- ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | STATIC | SPECIALIZED | SYNCHRONIZED
+ ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | STATIC | SPECIALIZED | SYNCHRONIZED | ARTIFACT
/** When a symbol for a field is created, only these flags survive
* from Modifiers. Others which may be applied at creation time are:
@@ -266,11 +268,13 @@ class Flags extends ModifierFlags {
final val GetterFlags = ~(PRESUPER | MUTABLE)
final val SetterFlags = ~(PRESUPER | MUTABLE | STABLE | CASEACCESSOR | IMPLICIT)
- /** 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.
+ /** Since DEFAULTPARAM is overloaded with TRAIT, we need some additional
+ * means of determining what that bit means. Usually DEFAULTPARAM is coupled
+ * with PARAM, which suffices. Default getters get METHOD instead.
+ * This constant is the mask of flags which can survive from the parameter modifiers.
+ * See paramFlagsToDefaultGetter for the full logic.
*/
- final val DefaultGetterFlags = PRIVATE | PROTECTED | FINAL
+ final val DefaultGetterFlags = PRIVATE | PROTECTED | FINAL | PARAMACCESSOR
/** When a symbol for a method parameter is created, only these flags survive
* from Modifiers. Others which may be applied at creation time are:
@@ -296,7 +300,11 @@ class Flags extends ModifierFlags {
assert((OverloadedFlagsMask & FlagsNotPickled) == 0, flagsToString(OverloadedFlagsMask & FlagsNotPickled))
/** These flags are pickled */
- final val PickledFlags = InitialFlags & ~FlagsNotPickled
+ final val PickledFlags = (
+ (InitialFlags & ~FlagsNotPickled)
+ | notPRIVATE // for value class constructors (SI-6601), and private members referenced
+ // in @inline-marked methods publicized in SuperAccessors (see SI-6608, e6b4204604)
+ )
/** If we have a top-level class or module
* and someone asks us for a flag not in TopLevelPickledFlags,
@@ -304,6 +312,9 @@ class Flags extends ModifierFlags {
*/
final val TopLevelPickledFlags = PickledFlags & ~(MODULE | METHOD | PACKAGE | PARAM | EXISTENTIAL)
+ def paramFlagsToDefaultGetter(paramFlags: Long): Long =
+ (paramFlags & DefaultGetterFlags) | SYNTHETIC | METHOD | DEFAULTPARAM
+
def getterFlags(fieldFlags: Long): Long = ACCESSOR + (
if ((fieldFlags & MUTABLE) != 0) fieldFlags & ~MUTABLE & ~PRESUPER
else fieldFlags & ~PRESUPER | STABLE
@@ -422,9 +433,9 @@ class Flags extends ModifierFlags {
case VARARGS => "<varargs>" // (1L << 43)
case TRIEDCOOKING => "<triedcooking>" // (1L << 44)
case SYNCHRONIZED => "<synchronized>" // (1L << 45)
- case 0x400000000000L => "" // (1L << 46)
+ case ARTIFACT => "<artifact>" // (1L << 46)
case DEFAULTMETHOD => "<defaultmethod>" // (1L << 47)
- case 0x1000000000000L => "" // (1L << 48)
+ case ENUM => "<enum>" // (1L << 48)
case 0x2000000000000L => "" // (1L << 49)
case 0x4000000000000L => "" // (1L << 50)
case `lateDEFERRED` => "<latedeferred>" // (1L << 51)
@@ -456,7 +467,7 @@ class Flags extends ModifierFlags {
)
@deprecated("Use flagString on the flag-carrying member", "2.10.0")
- def flagsToString(flags: Long, privateWithin: String): String = {
+ private[scala] def flagsToString(flags: Long, privateWithin: String): String = {
val access = accessString(flags, privateWithin)
val nonAccess = flagsToString(flags & ~AccessFlags)
@@ -464,7 +475,7 @@ class Flags extends ModifierFlags {
}
@deprecated("Use flagString on the flag-carrying member", "2.10.0")
- def flagsToString(flags: Long): String = {
+ private[scala] def flagsToString(flags: Long): String = {
// Fast path for common case
if (flags == 0L) "" else {
var sb: StringBuilder = null
@@ -497,4 +508,4 @@ class Flags extends ModifierFlags {
final val rawFlagPickledOrder: Array[Long] = pickledListOrder.toArray
}
-object Flags extends Flags { }
+object Flags extends Flags
diff --git a/src/reflect/scala/reflect/internal/FreshNames.scala b/src/reflect/scala/reflect/internal/FreshNames.scala
new file mode 100644
index 0000000000..7e9a568266
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/FreshNames.scala
@@ -0,0 +1,39 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ */
+
+package scala
+package reflect
+package internal
+
+import scala.reflect.internal.util.FreshNameCreator
+
+trait FreshNames { self: Names with StdNames =>
+ // SI-6879 Keeps track of counters that are supposed to be globally unique
+ // as opposed to traditional freshers that are unique to compilation units.
+ val globalFreshNameCreator = new FreshNameCreator
+
+ // default fresh name creator used to abstract over currentUnit.fresh and runtime fresh name creator
+ def currentFreshNameCreator: FreshNameCreator
+
+ // create fresh term/type name using implicit fresh name creator
+ def freshTermName(prefix: String = nme.FRESH_TERM_NAME_PREFIX)(implicit creator: FreshNameCreator): TermName = newTermName(creator.newName(prefix))
+ def freshTypeName(prefix: String)(implicit creator: FreshNameCreator): TypeName = newTypeName(creator.newName(prefix))
+
+ // Extractor that matches names which were generated by some
+ // FreshNameCreator with known prefix. Extracts user-specified
+ // prefix that was used as a parameter to newName by stripping
+ // global creator prefix and unique number in the end of the name.
+ class FreshNameExtractor(creatorPrefix: String = "") {
+ // quote prefix so that it can be used with replaceFirst
+ // which expects regExp rather than simple string
+ val quotedCreatorPrefix = java.util.regex.Pattern.quote(creatorPrefix)
+
+ def unapply(name: Name): Option[String] = {
+ val sname = name.toString
+ // name should start with creatorPrefix and end with number
+ if (!sname.startsWith(creatorPrefix) || !sname.matches("^.*\\d*$")) None
+ else Some(NameTransformer.decode(sname.replaceFirst(quotedCreatorPrefix, "").replaceAll("\\d*$", "")))
+ }
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/HasFlags.scala b/src/reflect/scala/reflect/internal/HasFlags.scala
index 12fd3a31cd..aa8f4c532e 100644
--- a/src/reflect/scala/reflect/internal/HasFlags.scala
+++ b/src/reflect/scala/reflect/internal/HasFlags.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package internal
import Flags._
@@ -80,8 +81,11 @@ trait HasFlags {
// identically, testing for a single flag.
def hasAbstractFlag = hasFlag(ABSTRACT)
def hasAccessorFlag = hasFlag(ACCESSOR)
- def hasDefault = hasAllFlags(DEFAULTPARAM | PARAM)
+ def hasDefault = hasFlag(DEFAULTPARAM) && hasFlag(METHOD | PARAM) // Second condition disambiguates with TRAIT
+ def hasEnumFlag = hasFlag(ENUM)
+ @deprecated("Use isLocalToThis instead", "2.11.0")
def hasLocalFlag = hasFlag(LOCAL)
+ def isLocalToThis = hasFlag(LOCAL)
def hasModuleFlag = hasFlag(MODULE)
def hasPackageFlag = hasFlag(PACKAGE)
def hasStableFlag = hasFlag(STABLE)
@@ -104,6 +108,7 @@ trait HasFlags {
def isOverride = hasFlag(OVERRIDE)
def isParamAccessor = hasFlag(PARAMACCESSOR)
def isPrivate = hasFlag(PRIVATE)
+ @deprecated ("Use `hasPackageFlag` instead", "2.11.0")
def isPackage = hasFlag(PACKAGE)
def isPrivateLocal = hasAllFlags(PrivateLocal)
def isProtected = hasFlag(PROTECTED)
@@ -161,15 +166,6 @@ trait HasFlags {
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")
+ // Guess this can't be deprecated seeing as it's in the reflect API.
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
index 9a8dee1f15..dc4ad25ef2 100644
--- a/src/reflect/scala/reflect/internal/Importers.scala
+++ b/src/reflect/scala/reflect/internal/Importers.scala
@@ -1,21 +1,23 @@
-package scala.reflect
+package scala
+package reflect
package internal
import scala.collection.mutable.WeakHashMap
import scala.ref.WeakReference
+import scala.reflect.internal.Flags._
// SI-6241: move importers to a mirror
-trait Importers extends api.Importers { self: SymbolTable =>
+trait Importers { to: SymbolTable =>
- def mkImporter(from0: api.Universe): Importer { val from: from0.type } = (
- if (self eq from0) {
+ override def mkImporter(from0: api.Universe): Importer { val from: from0.type } = (
+ if (to 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]
- def importPosition(pos: from.Position) = pos.asInstanceOf[self.Position]
+ val reverse = this.asInstanceOf[from.Importer{ val from: to.type }]
+ def importSymbol(their: from.Symbol) = their.asInstanceOf[to.Symbol]
+ def importType(their: from.Type) = their.asInstanceOf[to.Type]
+ def importTree(their: from.Tree) = their.asInstanceOf[to.Tree]
+ def importPosition(their: from.Position) = their.asInstanceOf[to.Position]
}
} else {
// todo. fix this loophole
@@ -28,8 +30,8 @@ trait Importers extends api.Importers { self: SymbolTable =>
val from: SymbolTable
- protected lazy val symMap = new Cache[from.Symbol, Symbol]()
- protected lazy val tpeMap = new Cache[from.Type, Type]()
+ protected lazy val symMap = new Cache[from.Symbol, to.Symbol]()
+ protected lazy val tpeMap = new Cache[from.Type, to.Type]()
protected class Cache[K <: AnyRef, V <: AnyRef] extends WeakHashMap[K, WeakReference[V]] {
def weakGet(key: K): Option[V] = this get key flatMap WeakReference.unapply
def weakUpdate(key: K, value: V) = this.update(key, WeakReference(value))
@@ -49,158 +51,164 @@ trait Importers extends api.Importers { self: SymbolTable =>
}
object reverse extends from.StandardImporter {
- val from: self.type = self
+ val from: to.type = to
// FIXME this and reverse should be constantly kept in sync
// not just synced once upon the first usage of reverse
- for ((fromsym, WeakReference(mysym)) <- StandardImporter.this.symMap) symMap += ((mysym, WeakReference(fromsym)))
- for ((fromtpe, WeakReference(mytpe)) <- StandardImporter.this.tpeMap) tpeMap += ((mytpe, WeakReference(fromtpe)))
+ for ((theirsym, WeakReference(mysym)) <- StandardImporter.this.symMap) symMap += ((mysym, WeakReference(theirsym)))
+ for ((theirtpe, WeakReference(mytpe)) <- StandardImporter.this.tpeMap) tpeMap += ((mytpe, WeakReference(theirtpe)))
}
- // todo. careful import of positions
- def importPosition(pos: from.Position): Position =
- pos.asInstanceOf[Position]
+ // ============== SYMBOLS ==============
+
+ protected def recreatedSymbolCompleter(my: to.Symbol, their: from.Symbol) = {
+ // we lock the symbol that is imported for a very short period of time
+ // i.e. only for when type parameters of the symbol are being imported
+ // the lock is used to communicate to the recursive importSymbol calls
+ // that type parameters need to be created from scratch
+ // because otherwise type parameters are imported by looking into owner.typeParams
+ // which is obviously unavailable while the completer is being created
+ try {
+ my setFlag Flags.LOCKED
+ val mytypeParams = their.typeParams map importSymbol
+ new LazyPolyType(mytypeParams) with FlagAgnosticCompleter {
+ override def complete(my: to.Symbol): Unit = {
+ val theirCore = their.info match {
+ case from.PolyType(_, core) => core
+ case core => core
+ }
+ my setInfo GenPolyType(mytypeParams, importType(theirCore))
+ my setAnnotations (their.annotations map importAnnotationInfo)
+ markAllCompleted(my)
+ }
+ }
+ } finally {
+ my resetFlag Flags.LOCKED
+ }
+ }
+
+ protected def recreateSymbol(their: from.Symbol): to.Symbol = {
+ val myowner = importSymbol(their.owner)
+ val mypos = importPosition(their.pos)
+ val myname = importName(their.name)
+ val myflags = their.flags
+ def linkReferenced(my: TermSymbol, their: from.TermSymbol, op: from.Symbol => Symbol): Symbol = {
+ symMap.weakUpdate(their, my)
+ my.referenced = op(their.referenced)
+ my
+ }
+ val my = their match {
+ case their: from.MethodSymbol =>
+ linkReferenced(myowner.newMethod(myname.toTermName, mypos, myflags), their, importSymbol)
+ case their: from.ModuleSymbol =>
+ val ret = linkReferenced(myowner.newModuleSymbol(myname.toTermName, mypos, myflags), their, importSymbol)
+ ret.associatedFile = their.associatedFile
+ ret
+ case their: from.FreeTermSymbol =>
+ newFreeTermSymbol(myname.toTermName, their.value, their.flags, their.origin) setInfo importType(their.info)
+ case their: from.FreeTypeSymbol =>
+ newFreeTypeSymbol(myname.toTypeName, their.flags, their.origin)
+ case their: from.TermSymbol =>
+ linkReferenced(myowner.newValue(myname.toTermName, mypos, myflags), their, importSymbol)
+ case their: from.TypeSkolem =>
+ val origin = their.unpackLocation match {
+ case null => null
+ case theirloc: from.Tree => importTree(theirloc)
+ case theirloc: from.Symbol => importSymbol(theirloc)
+ }
+ myowner.newTypeSkolemSymbol(myname.toTypeName, origin, mypos, myflags)
+ case their: from.ModuleClassSymbol =>
+ val my = myowner.newModuleClass(myname.toTypeName, mypos, myflags)
+ symMap.weakUpdate(their, my)
+ my.sourceModule = importSymbol(their.sourceModule)
+ my
+ case their: from.ClassSymbol =>
+ val my = myowner.newClassSymbol(myname.toTypeName, mypos, myflags)
+ symMap.weakUpdate(their, my)
+ if (their.thisSym != their) {
+ my.typeOfThis = importType(their.typeOfThis)
+ my.thisSym setName importName(their.thisSym.name)
+ }
+ my.associatedFile = their.associatedFile
+ my
+ case their: from.TypeSymbol =>
+ myowner.newTypeSymbol(myname.toTypeName, mypos, myflags)
+ }
+ symMap.weakUpdate(their, my)
+ markFlagsCompleted(my)(mask = AllFlags)
+ my setInfo recreatedSymbolCompleter(my, their)
+ }
- def importSymbol(sym0: from.Symbol): Symbol = {
- def doImport(sym: from.Symbol): Symbol =
- symMap weakGet sym match {
+ def importSymbol(their0: from.Symbol): Symbol = {
+ def cachedRecreateSymbol(their: from.Symbol): Symbol =
+ symMap weakGet their match {
case Some(result) => result
- case _ =>
- 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.weakUpdate(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, x.value, x.flags, x.origin) setInfo importType(x.info)
- case x: from.FreeTypeSymbol =>
- newFreeTypeSymbol(importName(x.name).toTypeName, 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.weakUpdate(x, mysym)
- mysym.sourceModule = importSymbol(x.sourceModule)
- mysym
- case x: from.ClassSymbol =>
- val mysym = myowner.newClassSymbol(myname.toTypeName, mypos, myflags)
- symMap.weakUpdate(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.weakUpdate(sym, mysym)
- mysym setFlag Flags.LOCKED
- mysym setInfo {
- val mytypeParams = sym.typeParams map importSymbol
- new LazyPolyType(mytypeParams) with FlagAgnosticCompleter {
- 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
+ case _ => recreateSymbol(their)
+ }
- def importOrRelink: Symbol = {
- val sym = sym0 // makes sym visible in the debugger
- if (sym == null)
+ def recreateOrRelink: Symbol = {
+ val their = their0 // makes their visible in the debugger
+ if (their == null)
null
- else if (sym == from.NoSymbol)
+ else if (their == from.NoSymbol)
NoSymbol
- else if (sym.isRoot)
+ else if (their.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)
+ val isModuleClass = their.isModuleClass
+ val isTparam = their.isTypeParameter && their.paramPos >= 0
+ val isOverloaded = their.isOverloaded
+
+ var theirscope = if (their.owner.isClass && !their.owner.isRefinementClass) their.owner.info else from.NoType
+ val theirexisting = if (isModuleClass) theirscope.decl(their.name).moduleClass else theirscope.decl(their.name)
+ if (!theirexisting.exists) theirscope = from.NoType
+
+ val myname = importName(their.name)
+ val myowner = importSymbol(their.owner)
+ val myscope = if (theirscope != from.NoType && !(myowner hasFlag Flags.LOCKED)) myowner.info else NoType
+ val myexisting = {
+ if (isModuleClass) importSymbol(their.sourceModule).moduleClass
+ else if (isTparam) (if (myowner hasFlag Flags.LOCKED) NoSymbol else myowner.typeParams(their.paramPos))
+ else if (isOverloaded) myowner.newOverloaded(myowner.thisType, their.alternatives map importSymbol)
+ else {
+ def disambiguate(my: Symbol) = {
+ val result =
+ if (their.isMethod) {
+ val localCopy = cachedRecreateSymbol(their)
+ my filter (_.tpe matches localCopy.tpe)
+ } else {
+ my filter (!_.isMethod)
+ }
+ assert(!result.isOverloaded,
+ "import failure: cannot determine unique overloaded method alternative from\n "+
+ (result.alternatives map (_.defString) mkString "\n")+"\n that matches "+their+":"+their.tpe)
+ result
}
- 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
- }
+ val myexisting = if (myscope != NoType) myscope.decl(myname) else NoSymbol
+ if (myexisting.isOverloaded) disambiguate(myexisting)
+ else myexisting
}
}
- mysym
+ myexisting.orElse {
+ val my = cachedRecreateSymbol(their)
+ if (myscope != NoType) {
+ assert(myscope.decls.lookup(myname) == NoSymbol, myname+" "+myscope.decl(myname)+" "+myexisting)
+ myscope.decls enter my
+ }
+ my
+ }
}
- } // end importOrRelink
+ } // end recreateOrRelink
- val sym = sym0
- symMap.weakGet(sym) match {
+ val their = their0
+ symMap.weakGet(their) match {
case Some(result) => result
case None =>
pendingSyms += 1
try {
- val result = importOrRelink
- symMap.weakUpdate(sym, result)
+ val result = recreateOrRelink
+ symMap.weakUpdate(their, result)
result
} finally {
pendingSyms -= 1
@@ -209,71 +217,72 @@ trait Importers extends api.Importers { self: SymbolTable =>
}
}
- 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.constr), 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)
+ // ============== TYPES ==============
+
+ def recreateType(their: from.Type): Type = their 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, result) =>
+ MethodType(params map importSymbol, importType(result))
+ case from.PolyType(tparams, result) =>
+ PolyType(tparams map importSymbol, importType(result))
+ case from.NullaryMethodType(result) =>
+ NullaryMethodType(importType(result))
+ 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(importType(bounds).asInstanceOf[TypeBounds])
+ 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(their.typeSymbol))
+ case from.ExistentialType(tparams, result) =>
+ newExistentialType(tparams map importSymbol, importType(result))
+ case from.OverloadedType(pre, alts) =>
+ OverloadedType(importType(pre), alts map importSymbol)
+ case from.ImportType(qual) =>
+ ImportType(importTree(qual))
+ case from.AntiPolyType(pre, targs) =>
+ AntiPolyType(importType(pre), targs map importType)
+ case their: from.TypeVar =>
+ val myconstr = new TypeConstraint(their.constr.loBounds map importType, their.constr.hiBounds map importType)
+ myconstr.inst = importType(their.constr.inst)
+ TypeVar(importType(their.origin), myconstr, their.typeArgs map importType, their.params map importSymbol)
+ case from.AnnotatedType(annots, result) =>
+ AnnotatedType(annots map importAnnotationInfo, importType(result))
+ case from.ErrorType =>
+ ErrorType
+ case from.WildcardType =>
+ WildcardType
+ case from.NoType =>
+ NoType
+ case from.NoPrefix =>
+ NoPrefix
+ case null =>
+ null
+ }
- tpeMap.weakGet(tpe) match {
+ def importType(their: from.Type): Type = {
+ tpeMap.weakGet(their) match {
case Some(result) => result
case None =>
pendingTpes += 1
try {
- val result = importOrRelink
- tpeMap.weakUpdate(tpe, result)
+ val result = recreateType(their)
+ tpeMap.weakUpdate(their, result)
result
} finally {
pendingTpes -= 1
@@ -282,7 +291,145 @@ trait Importers extends api.Importers { self: SymbolTable =>
}
}
- def importTypeBounds(bounds: from.TypeBounds) = importType(bounds).asInstanceOf[TypeBounds]
+ // ============== TREES ==============
+
+ def recreatedTreeCompleter(their: from.Tree, my: to.Tree): Unit = {
+ if (their.canHaveAttrs) {
+ if (my.hasSymbolField) my.symbol = importSymbol(their.symbol)
+ my.pos = importPosition(their.pos)
+ (their, my) match {
+ case (their: from.TypeTree, my: to.TypeTree) =>
+ if (their.wasEmpty) my.defineType(importType(their.tpe)) else my.setType(importType(their.tpe))
+ case (_, _) =>
+ my.tpe = importType(their.tpe)
+ }
+ }
+ }
+
+ def recreateTree(their: from.Tree): to.Tree = their 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.noSelfType =>
+ noSelfType
+ case from.pendingSuperCall =>
+ pendingSuperCall
+ 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) => their 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), importName(mix).toTypeName)
+ 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 theirtt @ from.TypeTree() =>
+ val mytt = TypeTree()
+ if (theirtt.original != null) mytt.setOriginal(importTree(theirtt.original))
+ mytt
+ 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 importMemberDef)
+ case from.EmptyTree =>
+ EmptyTree
+ case null =>
+ null
+ }
+
+ def importTree(their: from.Tree): Tree = {
+ val my = recreateTree(their)
+ if (my != null) {
+ addFixup(recreatedTreeCompleter(their, my))
+ tryFixup()
+ // we have to be careful with position import as some shared trees
+ // like EmptyTree, noSelfType don't support position assignment
+ if (their.pos != NoPosition) {
+ my.setPos(importPosition(their.pos))
+ }
+ }
+ importAttachments(their.attachments.all).foreach { my.updateAttachment(_) }
+ my
+ }
+
+ // ============== MISCELLANEOUS ==============
+
+ def importAttachments(attachments: Set[Any]): Set[Any] =
+ attachments.collect { case ia: ImportableAttachment => ia.importAttachment(this) }
def importAnnotationInfo(ann: from.AnnotationInfo): AnnotationInfo = {
val atp1 = importType(ann.atp)
@@ -301,13 +448,13 @@ trait Importers extends api.Importers { self: SymbolTable =>
ScalaSigBytes(bytes)
case from.NestedAnnotArg(annInfo) =>
NestedAnnotArg(importAnnotationInfo(annInfo))
+ case from.UnmappableAnnotArg =>
+ UnmappableAnnotArg
}
- 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. careful import of positions
+ def importPosition(their: from.Position): to.Position =
+ their.asInstanceOf[Position]
// !!! todo: override to cater for PackageScopes
def importScope(decls: from.Scope): Scope =
@@ -315,144 +462,15 @@ trait Importers extends api.Importers { self: SymbolTable =>
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()
- // we have to be careful with position import as some shared trees
- // like EmptyTree, emptyValDef don't support position assignment
- if (tree.pos != NoPosition)
- mytree.setPos(importPosition(tree.pos))
- else
- mytree
- }
-
def importValDef(tree: from.ValDef): ValDef = importTree(tree).asInstanceOf[ValDef]
def importTypeDef(tree: from.TypeDef): TypeDef = importTree(tree).asInstanceOf[TypeDef]
+ def importMemberDef(tree: from.MemberDef): MemberDef = importTree(tree).asInstanceOf[MemberDef]
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]
diff --git a/src/reflect/scala/reflect/internal/InfoTransformers.scala b/src/reflect/scala/reflect/internal/InfoTransformers.scala
index 82904b0b68..3814259e22 100644
--- a/src/reflect/scala/reflect/internal/InfoTransformers.scala
+++ b/src/reflect/scala/reflect/internal/InfoTransformers.scala
@@ -3,7 +3,8 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
trait InfoTransformers {
@@ -43,7 +44,7 @@ trait InfoTransformers {
if (from == this.pid) this
else if (from < this.pid)
if (prev.pid < from) this
- else prev.nextFrom(from);
+ else prev.nextFrom(from)
else if (next.pid == NoPhase.id) next
else next.nextFrom(from)
}
diff --git a/src/reflect/scala/reflect/internal/Internals.scala b/src/reflect/scala/reflect/internal/Internals.scala
new file mode 100644
index 0000000000..e9916cf7d1
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Internals.scala
@@ -0,0 +1,174 @@
+package scala
+package reflect
+package internal
+
+import scala.language.implicitConversions
+import scala.language.higherKinds
+import scala.collection.mutable.WeakHashMap
+import scala.ref.WeakReference
+import scala.reflect.api.Universe
+import scala.reflect.macros.Attachments
+import scala.reflect.internal.util.FreshNameCreator
+import scala.reflect.internal.Flags._
+import scala.reflect.internal.util.ListOfNil
+
+trait Internals extends api.Internals {
+ self: SymbolTable =>
+
+ type Internal = MacroInternalApi
+ lazy val internal: Internal = new SymbolTableInternal {}
+
+ type Compat = MacroCompatApi
+ lazy val compat: Compat = new Compat {}
+
+ trait SymbolTableInternal extends MacroInternalApi {
+ lazy val reificationSupport: ReificationSupportApi = self.build
+
+ def createImporter(from0: Universe): Importer { val from: from0.type } = self.mkImporter(from0)
+
+ def newScopeWith(elems: Symbol*): Scope = self.newScopeWith(elems: _*)
+ def enter(scope: Scope, sym: Symbol): scope.type = { scope.enter(sym); scope }
+ def unlink(scope: Scope, sym: Symbol): scope.type = { scope.unlink(sym); scope }
+
+ def freeTerms(tree: Tree): List[FreeTermSymbol] = tree.freeTerms
+ def freeTypes(tree: Tree): List[FreeTypeSymbol] = tree.freeTypes
+ def substituteSymbols(tree: Tree, from: List[Symbol], to: List[Symbol]): Tree = tree.substituteSymbols(from, to)
+ def substituteTypes(tree: Tree, from: List[Symbol], to: List[Type]): Tree = tree.substituteTypes(from, to)
+ def substituteThis(tree: Tree, clazz: Symbol, to: Tree): Tree = tree.substituteThis(clazz, to)
+ def attachments(tree: Tree): Attachments { type Pos = Position } = tree.attachments
+ def updateAttachment[T: ClassTag](tree: Tree, attachment: T): tree.type = tree.updateAttachment(attachment)
+ def removeAttachment[T: ClassTag](tree: Tree): tree.type = tree.removeAttachment[T]
+ def setPos(tree: Tree, newpos: Position): tree.type = tree.setPos(newpos)
+ def setType(tree: Tree, tp: Type): tree.type = tree.setType(tp)
+ def defineType(tree: Tree, tp: Type): tree.type = tree.defineType(tp)
+ def setSymbol(tree: Tree, sym: Symbol): tree.type = tree.setSymbol(sym)
+ def setOriginal(tt: TypeTree, tree: Tree): TypeTree = tt.setOriginal(tree)
+
+ def captureVariable(vble: Symbol): Unit = self.captureVariable(vble)
+ def referenceCapturedVariable(vble: Symbol): Tree = self.referenceCapturedVariable(vble)
+ def capturedVariableType(vble: Symbol): Type = self.capturedVariableType(vble)
+
+ def classDef(sym: Symbol, impl: Template): ClassDef = self.ClassDef(sym, impl)
+ def moduleDef(sym: Symbol, impl: Template): ModuleDef = self.ModuleDef(sym, impl)
+ def valDef(sym: Symbol, rhs: Tree): ValDef = self.ValDef(sym, rhs)
+ def valDef(sym: Symbol): ValDef = self.ValDef(sym)
+ def defDef(sym: Symbol, mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree): DefDef = self.DefDef(sym, mods, vparamss, rhs)
+ def defDef(sym: Symbol, vparamss: List[List[ValDef]], rhs: Tree): DefDef = self.DefDef(sym, vparamss, rhs)
+ def defDef(sym: Symbol, mods: Modifiers, rhs: Tree): DefDef = self.DefDef(sym, mods, rhs)
+ def defDef(sym: Symbol, rhs: Tree): DefDef = self.DefDef(sym, rhs)
+ def defDef(sym: Symbol, rhs: List[List[Symbol]] => Tree): DefDef = self.DefDef(sym, rhs)
+ def typeDef(sym: Symbol, rhs: Tree): TypeDef = self.TypeDef(sym, rhs)
+ def typeDef(sym: Symbol): TypeDef = self.TypeDef(sym)
+ def labelDef(sym: Symbol, params: List[Symbol], rhs: Tree): LabelDef = self.LabelDef(sym, params, rhs)
+
+ def changeOwner(tree: Tree, prev: Symbol, next: Symbol): tree.type = {
+ object changeOwnerAndModuleClassTraverser extends ChangeOwnerTraverser(prev, next) {
+ override def traverse(tree: Tree) {
+ tree match {
+ case _: DefTree => change(tree.symbol.moduleClass)
+ case _ => // do nothing
+ }
+ super.traverse(tree)
+ }
+ }
+ changeOwnerAndModuleClassTraverser.traverse(tree)
+ tree
+ }
+
+ lazy val gen = self.treeBuild
+
+ def isFreeTerm(symbol: Symbol): Boolean = symbol.isFreeTerm
+ def asFreeTerm(symbol: Symbol): FreeTermSymbol = symbol.asFreeTerm
+ def isFreeType(symbol: Symbol): Boolean = symbol.isFreeType
+ def asFreeType(symbol: Symbol): FreeTypeSymbol = symbol.asFreeType
+ def newTermSymbol(symbol: Symbol, name: TermName, pos: Position = NoPosition, flags: FlagSet = NoFlags): TermSymbol = symbol.newTermSymbol(name, pos, flags)
+ def newModuleAndClassSymbol(symbol: Symbol, name: Name, pos: Position = NoPosition, flags: FlagSet = NoFlags): (ModuleSymbol, ClassSymbol) = symbol.newModuleAndClassSymbol(name, pos, flags)
+ def newMethodSymbol(symbol: Symbol, name: TermName, pos: Position = NoPosition, flags: FlagSet = NoFlags): MethodSymbol = symbol.newMethodSymbol(name, pos, flags)
+ def newTypeSymbol(symbol: Symbol, name: TypeName, pos: Position = NoPosition, flags: FlagSet = NoFlags): TypeSymbol = symbol.newTypeSymbol(name, pos, flags)
+ def newClassSymbol(symbol: Symbol, name: TypeName, pos: Position = NoPosition, flags: FlagSet = NoFlags): ClassSymbol = symbol.newClassSymbol(name, pos, flags)
+ def newFreeTerm(name: String, value: => Any, flags: FlagSet = NoFlags, origin: String = null): FreeTermSymbol = reificationSupport.newFreeTerm(name, value, flags, origin)
+ def newFreeType(name: String, flags: FlagSet = NoFlags, origin: String = null): FreeTypeSymbol = reificationSupport.newFreeType(name, flags, origin)
+ def isErroneous(symbol: Symbol): Boolean = symbol.isErroneous
+ def isSkolem(symbol: Symbol): Boolean = symbol.isSkolem
+ def deSkolemize(symbol: Symbol): Symbol = symbol.deSkolemize
+ def initialize(symbol: Symbol): symbol.type = symbol.initialize
+ def fullyInitialize(symbol: Symbol): symbol.type = definitions.fullyInitializeSymbol(symbol).asInstanceOf[symbol.type]
+ def fullyInitialize(tp: Type): tp.type = definitions.fullyInitializeType(tp).asInstanceOf[tp.type]
+ def fullyInitialize(scope: Scope): scope.type = definitions.fullyInitializeScope(scope).asInstanceOf[scope.type]
+ def flags(symbol: Symbol): FlagSet = symbol.flags
+ def attachments(symbol: Symbol): Attachments { type Pos = Position } = symbol.attachments
+ def updateAttachment[T: ClassTag](symbol: Symbol, attachment: T): symbol.type = symbol.updateAttachment(attachment)
+ def removeAttachment[T: ClassTag](symbol: Symbol): symbol.type = symbol.removeAttachment[T]
+ def setOwner(symbol: Symbol, newowner: Symbol): symbol.type = { symbol.owner = newowner; symbol }
+ def setInfo(symbol: Symbol, tpe: Type): symbol.type = symbol.setInfo(tpe)
+ def setAnnotations(symbol: Symbol, annots: Annotation*): symbol.type = symbol.setAnnotations(annots: _*)
+ def setName(symbol: Symbol, name: Name): symbol.type = symbol.setName(name)
+ def setPrivateWithin(symbol: Symbol, sym: Symbol): symbol.type = symbol.setPrivateWithin(sym)
+ def setFlag(symbol: Symbol, flags: FlagSet): symbol.type = symbol.setFlag(flags)
+ def resetFlag(symbol: Symbol, flags: FlagSet): symbol.type = symbol.resetFlag(flags)
+
+ def thisType(sym: Symbol): Type = self.ThisType(sym)
+ def singleType(pre: Type, sym: Symbol): Type = self.SingleType(pre, sym)
+ def superType(thistpe: Type, supertpe: Type): Type = self.SuperType(thistpe, supertpe)
+ def constantType(value: Constant): ConstantType = self.ConstantType(value)
+ def typeRef(pre: Type, sym: Symbol, args: List[Type]): Type = self.TypeRef(pre, sym, args)
+ def refinedType(parents: List[Type], decls: Scope): RefinedType = self.RefinedType(parents, decls)
+ def refinedType(parents: List[Type], decls: Scope, clazz: Symbol): RefinedType = self.RefinedType(parents, decls, clazz)
+ def refinedType(parents: List[Type], owner: Symbol): Type = self.refinedType(parents, owner)
+ def refinedType(parents: List[Type], owner: Symbol, decls: Scope): Type = self.RefinedType(parents, decls, owner)
+ def refinedType(parents: List[Type], owner: Symbol, decls: Scope, pos: Position): Type = self.refinedType(parents, owner, decls, pos)
+ def intersectionType(tps: List[Type]): Type = self.intersectionType(tps)
+ def intersectionType(tps: List[Type], owner: Symbol): Type = self.intersectionType(tps, owner)
+ def classInfoType(parents: List[Type], decls: Scope, typeSymbol: Symbol): ClassInfoType = self.ClassInfoType(parents, decls, typeSymbol)
+ def methodType(params: List[Symbol], resultType: Type): MethodType = self.MethodType(params, resultType)
+ def nullaryMethodType(resultType: Type): NullaryMethodType = self.NullaryMethodType(resultType)
+ def polyType(typeParams: List[Symbol], resultType: Type): PolyType = self.PolyType(typeParams, resultType)
+ def existentialType(quantified: List[Symbol], underlying: Type): ExistentialType = self.ExistentialType(quantified, underlying)
+ def existentialAbstraction(tparams: List[Symbol], tpe0: Type): Type = self.existentialAbstraction(tparams, tpe0)
+ def annotatedType(annotations: List[Annotation], underlying: Type): AnnotatedType = self.AnnotatedType(annotations, underlying)
+ def typeBounds(lo: Type, hi: Type): TypeBounds = self.TypeBounds(lo, hi)
+ def boundedWildcardType(bounds: TypeBounds): BoundedWildcardType = self.BoundedWildcardType(bounds)
+
+ def subpatterns(tree: Tree): Option[List[Tree]] = tree.attachments.get[SubpatternsAttachment].map(_.patterns.map(_.duplicate))
+
+ type Decorators = MacroDecoratorApi
+ lazy val decorators: Decorators = new MacroDecoratorApi {
+ override type ScopeDecorator[T <: Scope] = MacroScopeDecoratorApi[T]
+ override implicit def scopeDecorator[T <: Scope](scope: T): ScopeDecorator[T] = new MacroScopeDecoratorApi[T](scope)
+ override type TreeDecorator[T <: Tree] = MacroTreeDecoratorApi[T]
+ override implicit def treeDecorator[T <: Tree](tree: T): TreeDecorator[T] = new MacroTreeDecoratorApi[T](tree)
+ override type TypeTreeDecorator[T <: TypeTree] = MacroTypeTreeDecoratorApi[T]
+ override implicit def typeTreeDecorator[T <: TypeTree](tt: T): TypeTreeDecorator[T] = new MacroTypeTreeDecoratorApi[T](tt)
+ override type SymbolDecorator[T <: Symbol] = MacroSymbolDecoratorApi[T]
+ override implicit def symbolDecorator[T <: Symbol](symbol: T): SymbolDecorator[T] = new MacroSymbolDecoratorApi[T](symbol)
+ override type TypeDecorator[T <: Type] = TypeDecoratorApi[T]
+ override implicit def typeDecorator[T <: Type](tp: T): TypeDecorator[T] = new TypeDecoratorApi[T](tp)
+ }
+ }
+
+ lazy val treeBuild = new self.TreeGen {
+ def mkAttributedQualifier(tpe: Type): Tree = self.gen.mkAttributedQualifier(tpe)
+ def mkAttributedQualifier(tpe: Type, termSym: Symbol): Tree = self.gen.mkAttributedQualifier(tpe, termSym)
+ def mkAttributedRef(pre: Type, sym: Symbol): RefTree = self.gen.mkAttributedRef(pre, sym)
+ def mkAttributedRef(sym: Symbol): RefTree = self.gen.mkAttributedRef(sym)
+ def stabilize(tree: Tree): Tree = self.gen.stabilize(tree)
+ def mkAttributedStableRef(pre: Type, sym: Symbol): Tree = self.gen.mkAttributedStableRef(pre, sym)
+ def mkAttributedStableRef(sym: Symbol): Tree = self.gen.mkAttributedStableRef(sym)
+ def mkUnattributedRef(sym: Symbol): RefTree = self.gen.mkUnattributedRef(sym)
+ def mkUnattributedRef(fullName: Name): RefTree = self.gen.mkUnattributedRef(fullName)
+ def mkAttributedThis(sym: Symbol): This = self.gen.mkAttributedThis(sym)
+ def mkAttributedIdent(sym: Symbol): RefTree = self.gen.mkAttributedIdent(sym)
+ def mkAttributedSelect(qual: Tree, sym: Symbol): RefTree = self.gen.mkAttributedSelect(qual, sym)
+ def mkMethodCall(receiver: Symbol, methodName: Name, targs: List[Type], args: List[Tree]): Tree = self.gen.mkMethodCall(receiver, methodName, targs, args)
+ def mkMethodCall(method: Symbol, targs: List[Type], args: List[Tree]): Tree = self.gen.mkMethodCall(method, targs, args)
+ def mkMethodCall(method: Symbol, args: List[Tree]): Tree = self.gen.mkMethodCall(method, args)
+ def mkMethodCall(target: Tree, args: List[Tree]): Tree = self.gen.mkMethodCall(target, args)
+ def mkMethodCall(receiver: Symbol, methodName: Name, args: List[Tree]): Tree = self.gen.mkMethodCall(receiver, methodName, args)
+ def mkMethodCall(receiver: Tree, method: Symbol, targs: List[Type], args: List[Tree]): Tree = self.gen.mkMethodCall(receiver, method, targs, args)
+ def mkMethodCall(target: Tree, targs: List[Type], args: List[Tree]): Tree = self.gen.mkMethodCall(target, targs, args)
+ def mkNullaryCall(method: Symbol, targs: List[Type]): Tree = self.gen.mkNullaryCall(method, targs)
+ def mkRuntimeUniverseRef: Tree = self.gen.mkRuntimeUniverseRef
+ def mkZero(tp: Type): Tree = self.gen.mkZero(tp)
+ def mkCast(tree: Tree, pt: Type): Tree = self.gen.mkCast(tree, pt)
+ }
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/internal/JMethodOrConstructor.scala b/src/reflect/scala/reflect/internal/JMethodOrConstructor.scala
new file mode 100644
index 0000000000..fb1cdb34e1
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/JMethodOrConstructor.scala
@@ -0,0 +1,47 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ * @author Paul Phillips
+ */
+package scala
+package reflect
+package internal
+
+import scala.language.implicitConversions
+import java.lang.{ Class => jClass }
+import java.lang.annotation.{ Annotation => jAnnotation }
+import java.lang.reflect.{
+ Member => jMember, Constructor => jConstructor, Method => jMethod,
+ AnnotatedElement => jAnnotatedElement, Type => jType,
+ TypeVariable => jTypeVariable
+}
+
+/** This class tries to abstract over some of the duplication
+ * in java.lang.reflect.{ Method, Constructor }.
+ */
+class JMethodOrConstructor(val member: jMember with jAnnotatedElement) {
+ def isVarArgs: Boolean = member match {
+ case m: jMethod => m.isVarArgs
+ case m: jConstructor[_] => m.isVarArgs
+ }
+ def typeParams: Array[_ <: jTypeVariable[_]] = member match {
+ case m: jMethod => m.getTypeParameters
+ case m: jConstructor[_] => m.getTypeParameters
+ }
+ def paramTypes: Array[jType] = member match {
+ case m: jMethod => m.getGenericParameterTypes
+ case m: jConstructor[_] => m.getGenericParameterTypes
+ }
+ def paramAnnotations: Array[Array[jAnnotation]] = member match {
+ case m: jMethod => m.getParameterAnnotations
+ case m: jConstructor[_] => m.getParameterAnnotations
+ }
+ def resultType: jType = member match {
+ case m: jMethod => m.getGenericReturnType
+ case m: jConstructor[_] => classOf[Unit]
+ }
+}
+
+object JMethodOrConstructor {
+ implicit def liftMethodToJmoc(m: jMethod): JMethodOrConstructor = new JMethodOrConstructor(m)
+ implicit def liftConstructorToJmoc(m: jConstructor[_]): JMethodOrConstructor = new JMethodOrConstructor(m)
+}
diff --git a/src/reflect/scala/reflect/internal/JavaAccFlags.scala b/src/reflect/scala/reflect/internal/JavaAccFlags.scala
new file mode 100644
index 0000000000..0a33b8cf0d
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/JavaAccFlags.scala
@@ -0,0 +1,84 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ * @author Paul Phillips
+ */
+package scala
+package reflect
+package internal
+
+import java.lang.{ Class => jClass }
+import java.lang.reflect.{ Member => jMember, Constructor => jConstructor, Field => jField, Method => jMethod }
+import JavaAccFlags._
+import ClassfileConstants._
+
+/** A value class which encodes the access_flags (JVMS 4.1)
+ * for a field, method, or class. The low 16 bits are the same
+ * as those returned by java.lang.reflect.Member#getModifiers
+ * and found in the bytecode.
+ *
+ * The high bits encode whether the access flags are directly
+ * associated with a class, constructor, field, or method.
+ */
+final class JavaAccFlags private (val coded: Int) extends AnyVal {
+ private def has(mask: Int) = (flags & mask) != 0
+ private def flagCarrierId = coded >>> 16
+ private def flags = coded & 0xFFFF
+
+ def isAbstract = has(JAVA_ACC_ABSTRACT)
+ def isAnnotation = has(JAVA_ACC_ANNOTATION)
+ def isBridge = has(JAVA_ACC_BRIDGE)
+ def isEnum = has(JAVA_ACC_ENUM)
+ def isFinal = has(JAVA_ACC_FINAL)
+ def isInterface = has(JAVA_ACC_INTERFACE)
+ def isNative = has(JAVA_ACC_NATIVE)
+ def isPrivate = has(JAVA_ACC_PRIVATE)
+ def isProtected = has(JAVA_ACC_PROTECTED)
+ def isPublic = has(JAVA_ACC_PUBLIC)
+ def isStatic = has(JAVA_ACC_STATIC)
+ def isStrictFp = has(JAVA_ACC_STRICT)
+ def isSuper = has(JAVA_ACC_SUPER)
+ def isSynchronized = has(JAVA_ACC_SYNCHRONIZED)
+ def isSynthetic = has(JAVA_ACC_SYNTHETIC)
+ def isTransient = has(JAVA_ACC_TRANSIENT)
+ def isVarargs = has(JAVA_ACC_VARARGS)
+ def isVolatile = has(JAVA_ACC_VOLATILE)
+
+ /** Do these flags describe a member which has either protected or package access?
+ * Such access in java is encoded in scala as protected[foo] or private[foo], where
+ * `foo` is the defining package.
+ */
+ def hasPackageAccessBoundary = !has(JAVA_ACC_PRIVATE | JAVA_ACC_PUBLIC) // equivalently, allows protected or package level access
+ def isPackageProtected = !has(JAVA_ACC_PRIVATE | JAVA_ACC_PROTECTED | JAVA_ACC_PUBLIC)
+
+ def toJavaFlags: Int = flags
+ def toScalaFlags: Long = flagCarrierId match {
+ case Method | Constructor => FlagTranslation methodFlags flags
+ case Class => FlagTranslation classFlags flags
+ case _ => FlagTranslation fieldFlags flags
+ }
+}
+
+object JavaAccFlags {
+ private val Unknown = 0
+ private val Class = 1
+ private val Field = 2
+ private val Method = 3
+ private val Constructor = 4
+
+ private def create(flagCarrier: Int, access_flags: Int): JavaAccFlags =
+ new JavaAccFlags((flagCarrier << 16) | (access_flags & 0xFFFF))
+
+ def classFlags(flags: Int): JavaAccFlags = create(Class, flags)
+ def methodFlags(flags: Int): JavaAccFlags = create(Method, flags)
+ def fieldFlags(flags: Int): JavaAccFlags = create(Field, flags)
+ def constructorFlags(flags: Int): JavaAccFlags = create(Constructor, flags)
+
+ def apply(access_flags: Int): JavaAccFlags = create(Unknown, access_flags)
+ def apply(clazz: jClass[_]): JavaAccFlags = classFlags(clazz.getModifiers)
+ def apply(member: jMember): JavaAccFlags = member match {
+ case x: jConstructor[_] => constructorFlags(x.getModifiers)
+ case x: jMethod => methodFlags(x.getModifiers)
+ case x: jField => fieldFlags(x.getModifiers)
+ case _ => apply(member.getModifiers)
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/Kinds.scala b/src/reflect/scala/reflect/internal/Kinds.scala
index 3ab7b20ecd..8ae201f045 100644
--- a/src/reflect/scala/reflect/internal/Kinds.scala
+++ b/src/reflect/scala/reflect/internal/Kinds.scala
@@ -3,7 +3,8 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
import scala.collection.{ mutable, immutable }
@@ -36,7 +37,7 @@ trait Kinds {
private def varStr(s: Symbol): String =
if (s.isCovariant) "covariant"
else if (s.isContravariant) "contravariant"
- else "invariant";
+ 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)) ""
@@ -86,15 +87,15 @@ trait Kinds {
// 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
+ checkKindBounds0(tparams, targs, pre, owner, explainErrors = 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
+ sym2.variance.isInvariant
+ || sym1.variance == sym2.variance
)
/** Check well-kindedness of type application (assumes arities are already checked) -- @M
@@ -145,7 +146,7 @@ trait Kinds {
kindErrors = f(kindErrors)
}
- if (settings.debug.value) {
+ if (settings.debug) {
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)
@@ -202,7 +203,7 @@ trait Kinds {
else NoKindErrors
}
- if (settings.debug.value && (tparams.nonEmpty || targs.nonEmpty)) log(
+ if (settings.debug && (tparams.nonEmpty || targs.nonEmpty)) log(
"checkKindBounds0(" + tparams + ", " + targs + ", " + pre + ", "
+ owner + ", " + explainErrors + ")"
)
@@ -230,4 +231,182 @@ trait Kinds {
}
}
}
+
+ /**
+ * The data structure describing the kind of a given type.
+ *
+ * Proper types are represented using ProperTypeKind.
+ *
+ * Type constructors are reprented using TypeConKind.
+ */
+ abstract class Kind {
+ import Kind.StringState
+ def description: String
+ def order: Int
+ def bounds: TypeBounds
+
+ /** Scala syntax notation of this kind.
+ * Proper types are expresses as A.
+ * Type constructors are expressed as F[k1 >: lo <: hi, k2, ...] where k1, k2, ... are parameter kinds.
+ * If the bounds exists at any level, it preserves the type variable names. Otherwise,
+ * it uses prescribed letters for each level: A, F, X, Y, Z.
+ */
+ def scalaNotation: String
+
+ /** Kind notation used in http://adriaanm.github.com/files/higher.pdf.
+ * Proper types are expressed as *.
+ * Type constructors are expressed * -> *(lo, hi) -(+)-> *.
+ */
+ def starNotation: String
+
+ /** Contains bounds either as part of itself or its arguments.
+ */
+ def hasBounds: Boolean = !bounds.isEmptyBounds
+
+ private[internal] def buildState(sym: Symbol, v: Variance)(s: StringState): StringState
+ }
+ object Kind {
+ private[internal] sealed trait ScalaNotation
+ private[internal] sealed case class Head(order: Int, n: Option[Int], alias: Option[String]) extends ScalaNotation {
+ override def toString: String = {
+ alias getOrElse {
+ typeAlias(order) + n.map(_.toString).getOrElse("")
+ }
+ }
+ private def typeAlias(x: Int): String =
+ x match {
+ case 0 => "A"
+ case 1 => "F"
+ case 2 => "X"
+ case 3 => "Y"
+ case 4 => "Z"
+ case n if n < 12 => ('O'.toInt - 5 + n).toChar.toString
+ case _ => "V"
+ }
+ }
+ private[internal] sealed case class Text(value: String) extends ScalaNotation {
+ override def toString: String = value
+ }
+ private[internal] case class StringState(tokens: Seq[ScalaNotation]) {
+ override def toString: String = tokens.mkString
+ def append(value: String): StringState = StringState(tokens :+ Text(value))
+ def appendHead(order: Int, sym: Symbol): StringState = {
+ val n = countByOrder(order) + 1
+ val alias = if (sym eq NoSymbol) None
+ else Some(sym.nameString)
+ StringState(tokens :+ Head(order, Some(n), alias))
+ }
+ def countByOrder(o: Int): Int = tokens count {
+ case Head(`o`, _, _) => true
+ case t => false
+ }
+ // Replace Head(o, Some(1), a) with Head(o, None, a) if countByOrder(o) <= 1, so F1[A] becomes F[A]
+ def removeOnes: StringState = {
+ val maxOrder = (tokens map {
+ case Head(o, _, _) => o
+ case _ => 0
+ }).max
+ StringState((tokens /: (0 to maxOrder)) { (ts: Seq[ScalaNotation], o: Int) =>
+ if (countByOrder(o) <= 1)
+ ts map {
+ case Head(`o`, _, a) => Head(o, None, a)
+ case t => t
+ }
+ else ts
+ })
+ }
+ // Replace Head(o, n, Some(_)) with Head(o, n, None), so F[F] becomes F[A].
+ def removeAlias: StringState = {
+ StringState(tokens map {
+ case Head(o, n, Some(_)) => Head(o, n, None)
+ case t => t
+ })
+ }
+ }
+ private[internal] object StringState {
+ def empty: StringState = StringState(Seq())
+ }
+ def FromParams(tparams: List[Symbol]): Type = GenPolyType(tparams, AnyTpe)
+ def Wildcard: Type = WildcardType
+ }
+ class ProperTypeKind(val bounds: TypeBounds) extends Kind {
+ import Kind.StringState
+ val description: String = "This is a proper type."
+ val order = 0
+ private[internal] def buildState(sym: Symbol, v: Variance)(s: StringState): StringState = {
+ s.append(v.symbolicString).appendHead(order, sym).append(bounds.scalaNotation(_.toString))
+ }
+ def scalaNotation: String = Kind.Head(order, None, None) + bounds.scalaNotation(_.toString)
+ def starNotation: String = "*" + bounds.starNotation(_.toString)
+ }
+ object ProperTypeKind {
+ def apply: ProperTypeKind = this(TypeBounds.empty)
+ def apply(bounds: TypeBounds): ProperTypeKind = new ProperTypeKind(bounds)
+ def unapply(ptk: ProperTypeKind): Some[TypeBounds] = Some(ptk.bounds)
+ }
+
+ class TypeConKind(val bounds: TypeBounds, val args: Seq[TypeConKind.Argument]) extends Kind {
+ import Kind.StringState
+ val order = (args map (_.kind.order)).max + 1
+ def description: String =
+ if (order == 1) "This is a type constructor: a 1st-order-kinded type."
+ else "This is a type constructor that takes type constructor(s): a higher-kinded type."
+ override def hasBounds: Boolean = super.hasBounds || args.exists(_.kind.hasBounds)
+ def scalaNotation: String = {
+ val s = buildState(NoSymbol, Variance.Invariant)(StringState.empty).removeOnes
+ val s2 = if (hasBounds) s
+ else s.removeAlias
+ s2.toString
+ }
+ private[internal] def buildState(sym: Symbol, v: Variance)(s0: StringState): StringState = {
+ var s: StringState = s0
+ s = s.append(v.symbolicString).appendHead(order, sym).append("[")
+ args.zipWithIndex foreach { case (arg, i) =>
+ s = arg.kind.buildState(arg.sym, arg.variance)(s)
+ if (i != args.size - 1) {
+ s = s.append(",")
+ }
+ }
+ s = s.append("]").append(bounds.scalaNotation(_.toString))
+ s
+ }
+ def starNotation: String = {
+ import Variance._
+ (args map { arg =>
+ (if (arg.kind.order == 0) arg.kind.starNotation
+ else "(" + arg.kind.starNotation + ")") +
+ (if (arg.variance == Invariant) " -> "
+ else " -(" + arg.variance.symbolicString + ")-> ")
+ }).mkString + "*" + bounds.starNotation(_.toString)
+ }
+ }
+ object TypeConKind {
+ def apply(args: Seq[TypeConKind.Argument]): TypeConKind = this(TypeBounds.empty, args)
+ def apply(bounds: TypeBounds, args: Seq[TypeConKind.Argument]): TypeConKind = new TypeConKind(bounds, args)
+ def unapply(tck: TypeConKind): Some[(TypeBounds, Seq[TypeConKind.Argument])] = Some((tck.bounds, tck.args))
+ case class Argument(variance: Variance, kind: Kind)(val sym: Symbol) {}
+ }
+
+ /**
+ * Starting from a Symbol (sym) or a Type (tpe), infer the kind that classifies it (sym.tpeHK/tpe).
+ */
+ object inferKind {
+ import TypeConKind.Argument
+
+ abstract class InferKind {
+ protected def infer(tpe: Type, owner: Symbol, topLevel: Boolean): Kind
+ protected def infer(sym: Symbol, topLevel: Boolean): Kind = infer(sym.tpeHK, sym.owner, topLevel)
+ def apply(sym: Symbol): Kind = infer(sym, true)
+ def apply(tpe: Type, owner: Symbol): Kind = infer(tpe, owner, true)
+ }
+
+ def apply(pre: Type): InferKind = new InferKind {
+ protected def infer(tpe: Type, owner: Symbol, topLevel: Boolean): Kind = {
+ val bounds = if (topLevel) TypeBounds.empty
+ else tpe.asSeenFrom(pre, owner).bounds
+ if(!tpe.isHigherKinded) ProperTypeKind(bounds)
+ else TypeConKind(bounds, tpe.typeParams map { p => Argument(p.variance, infer(p, false))(p) })
+ }
+ }
+ }
}
diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala
index 0beb8e368f..4a35e024de 100644
--- a/src/reflect/scala/reflect/internal/Mirrors.scala
+++ b/src/reflect/scala/reflect/internal/Mirrors.scala
@@ -3,7 +3,8 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
import Flags._
@@ -19,6 +20,8 @@ trait Mirrors extends api.Mirrors {
trait RootSymbol extends Symbol { def mirror: Mirror }
abstract class RootsBase(rootOwner: Symbol) extends scala.reflect.api.Mirror[Mirrors.this.type] { thisMirror =>
+ private[this] var initialized = false
+ def isMirrorInitialized = initialized
protected[scala] def rootLoader: LazyType
@@ -27,24 +30,26 @@ trait Mirrors extends api.Mirrors {
val EmptyPackageClass: ClassSymbol
val EmptyPackage: ModuleSymbol
+ def symbolOf[T: universe.WeakTypeTag]: universe.TypeSymbol = universe.weakTypeTag[T].in(this).tpe.typeSymbolDirect.asType
+
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 */
+ /** Todo: organize similar to mkStatic in scala.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)
- var sym = owner.info member name
+ 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
+ if (settings.debug) { log(sym.info); log(sym.info.members) }//debug
thisMirror.missingHook(owner, name) orElse {
MissingRequirementError.notFound((if (path.isTermName) "object " else "class ")+path+" in "+thisMirror)
}
@@ -76,7 +81,9 @@ trait Mirrors extends api.Mirrors {
protected def universeMissingHook(owner: Symbol, name: Name): Symbol = thisUniverse.missingHook(owner, name)
- private[scala] def missingHook(owner: Symbol, name: Name): Symbol = mirrorMissingHook(owner, name) orElse universeMissingHook(owner, name)
+ private[scala] def missingHook(owner: Symbol, name: Name): Symbol = logResult(s"missingHook($owner, $name)")(
+ mirrorMissingHook(owner, name) orElse universeMissingHook(owner, name)
+ )
// todo: get rid of most the methods here and keep just staticClass/Module/Package
@@ -91,10 +98,6 @@ trait Mirrors extends api.Mirrors {
}
}
- @deprecated("Use getClassByName", "2.10.0")
- def getClass(fullname: Name): ClassSymbol =
- getClassByName(fullname)
-
def getClassByName(fullname: Name): ClassSymbol =
ensureClassSymbol(fullname.toString, getModuleOrClass(fullname.toTypeName))
@@ -116,25 +119,22 @@ trait Mirrors extends api.Mirrors {
* Compiler might ignore them, but they should be loadable with macros.
*/
override def staticClass(fullname: String): ClassSymbol =
- ensureClassSymbol(fullname, staticModuleOrClass(newTypeNameCached(fullname)))
+ try ensureClassSymbol(fullname, staticModuleOrClass(newTypeNameCached(fullname)))
+ catch { case mre: MissingRequirementError => throw new ScalaReflectionException(mre.msg) }
/************************ loaders of module symbols ************************/
private def ensureModuleSymbol(fullname: String, sym: Symbol, allowPackages: Boolean): ModuleSymbol =
sym match {
- case x: ModuleSymbol if allowPackages || !x.isPackage => x
- case _ => MissingRequirementError.notFound("object " + fullname)
+ case x: ModuleSymbol if allowPackages || !x.hasPackageFlag => x
+ case _ => MissingRequirementError.notFound("object " + fullname)
}
- @deprecated("Use getModuleByName", "2.10.0")
- def getModule(fullname: Name): ModuleSymbol =
- getModuleByName(fullname)
-
def getModuleByName(fullname: Name): ModuleSymbol =
ensureModuleSymbol(fullname.toString, getModuleOrClass(fullname.toTermName), allowPackages = true)
def getRequiredModule(fullname: String): ModuleSymbol =
- getModule(newTermNameCached(fullname))
+ getModuleByName(newTermNameCached(fullname))
// 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
@@ -150,7 +150,7 @@ trait Mirrors extends api.Mirrors {
getModuleIfDefined(newTermNameCached(fullname))
def getModuleIfDefined(fullname: Name): Symbol =
- wrapMissing(getModule(fullname.toTermName))
+ wrapMissing(getModuleByName(fullname.toTermName))
/** @inheritdoc
*
@@ -158,24 +158,29 @@ trait Mirrors extends api.Mirrors {
* Compiler might ignore them, but they should be loadable with macros.
*/
override def staticModule(fullname: String): ModuleSymbol =
- ensureModuleSymbol(fullname, staticModuleOrClass(newTermNameCached(fullname)), allowPackages = false)
+ try ensureModuleSymbol(fullname, staticModuleOrClass(newTermNameCached(fullname)), allowPackages = false)
+ catch { case mre: MissingRequirementError => throw new ScalaReflectionException(mre.msg) }
/************************ loaders of package symbols ************************/
private def ensurePackageSymbol(fullname: String, sym: Symbol, allowModules: Boolean): ModuleSymbol =
sym match {
- case x: ModuleSymbol if allowModules || x.isPackage => x
- case _ => MissingRequirementError.notFound("package " + fullname)
+ case x: ModuleSymbol if allowModules || x.hasPackageFlag => x
+ case _ => MissingRequirementError.notFound("package " + fullname)
}
- def getPackage(fullname: Name): ModuleSymbol =
+ def getPackage(fullname: TermName): ModuleSymbol =
ensurePackageSymbol(fullname.toString, getModuleOrClass(fullname), allowModules = true)
- def getRequiredPackage(fullname: String): ModuleSymbol =
+ def getPackageIfDefined(fullname: TermName): Symbol =
+ wrapMissing(getPackage(fullname))
+
+ @deprecated("Use getPackage", "2.11.0") def getRequiredPackage(fullname: String): ModuleSymbol =
getPackage(newTermNameCached(fullname))
- def getPackageObject(fullname: String): ModuleSymbol =
- (getPackage(newTermName(fullname)).info member nme.PACKAGE) match {
+ def getPackageObject(fullname: String): ModuleSymbol = getPackageObject(newTermName(fullname))
+ def getPackageObject(fullname: TermName): ModuleSymbol =
+ (getPackage(fullname).info member nme.PACKAGE) match {
case x: ModuleSymbol => x
case _ => MissingRequirementError.notFound("package object " + fullname)
}
@@ -183,17 +188,27 @@ trait Mirrors extends api.Mirrors {
def getPackageObjectIfDefined(fullname: String): Symbol =
getPackageObjectIfDefined(newTermNameCached(fullname))
- def getPackageObjectIfDefined(fullname: Name): Symbol =
- wrapMissing(getPackageObject(fullname.toTermName))
+ def getPackageObjectIfDefined(fullname: TermName): Symbol =
+ wrapMissing(getPackageObject(fullname))
+
+ final def getPackageObjectWithMember(pre: Type, sym: Symbol): Symbol = {
+ // The owner of a symbol which requires package qualification may be the
+ // package object iself, but it also could be any superclass of the package
+ // object. In the latter case, we must go through the qualifier's info
+ // to obtain the right symbol.
+ if (sym.owner.isModuleClass) sym.owner.sourceModule // fast path, if the member is owned by a module class, that must be linked to the package object
+ else pre member nme.PACKAGE // otherwise we have to findMember
+ }
override def staticPackage(fullname: String): ModuleSymbol =
- ensurePackageSymbol(fullname.toString, getModuleOrClass(newTermNameCached(fullname)), allowModules = false)
+ try ensurePackageSymbol(fullname.toString, getModuleOrClass(newTermNameCached(fullname)), allowModules = false)
+ catch { case mre: MissingRequirementError => throw new ScalaReflectionException(mre.msg) }
/************************ helpers ************************/
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.
+ /* 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) + "]"
@@ -202,7 +217,7 @@ trait Mirrors extends api.Mirrors {
erasureString(classTag[T].runtimeClass)
}
- @inline private def wrapMissing(body: => Symbol): Symbol =
+ @inline final def wrapMissing(body: => Symbol): Symbol =
try body
catch { case _: MissingRequirementError => NoSymbol }
@@ -228,6 +243,7 @@ trait Mirrors extends api.Mirrors {
// }
def init() {
+ if (initialized) return
// 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.
@@ -239,6 +255,21 @@ trait Mirrors extends api.Mirrors {
RootClass.info.decls enter EmptyPackage
RootClass.info.decls enter RootPackage
+
+ if (rootOwner != NoSymbol) {
+ // synthetic core classes are only present in root mirrors
+ // because Definitions.scala, which initializes and enters them, only affects rootMirror
+ // therefore we need to enter them manually for non-root mirrors
+ definitions.syntheticCoreClasses foreach (theirSym => {
+ val theirOwner = theirSym.owner
+ assert(theirOwner.isPackageClass, s"theirSym = $theirSym, theirOwner = $theirOwner")
+ val ourOwner = staticPackage(theirOwner.fullName).moduleClass
+ val ourSym = theirSym // just copy the symbol into our branch of the symbol table
+ ourOwner.info.decls enterIfNew ourSym
+ })
+ }
+
+ initialized = true
}
}
@@ -262,34 +293,46 @@ trait Mirrors extends api.Mirrors {
def mirror = thisMirror.asInstanceOf[Mirror]
}
- // This is the package _root_. The actual root cannot be referenced at
- // the source level, but _root_ is essentially a function => <root>.
- final object RootPackage extends ModuleSymbol(rootOwner, NoPosition, nme.ROOTPKG) with RootSymbol {
+ class RootPackage extends ModuleSymbol(rootOwner, NoPosition, nme.ROOTPKG) with RootSymbol {
this setInfo NullaryMethodType(RootClass.tpe)
- RootClass.sourceModule = this
override def isRootPackage = true
}
+
+ // This is the package _root_. The actual root cannot be referenced at
+ // the source level, but _root_ is essentially a function => <root>.
+ lazy val RootPackage = new RootPackage
+
+ class RootClass extends PackageClassSymbol(rootOwner, NoPosition, tpnme.ROOT) with RootSymbol {
+ this setInfo rootLoader
+
+ override def isRoot = true
+ override def isEffectiveRoot = true
+ override def isNestedClass = false
+ override def sourceModule = RootPackage
+ }
+
// This is <root>, the actual root of everything except the package _root_.
// <root> and _root_ (RootPackage and RootClass) should be the only "well known"
// symbols owned by NoSymbol. All owner chains should go through RootClass,
// although it is probable that some symbols are created as direct children
// of NoSymbol to ensure they will not be stumbled upon. (We should designate
// a better encapsulated place for that.)
- final object RootClass extends PackageClassSymbol(rootOwner, NoPosition, tpnme.ROOT) with RootSymbol {
- this setInfo rootLoader
+ lazy val RootClass = new RootClass
- override def isRoot = true
- override def isEffectiveRoot = true
- override def isNestedClass = false
- }
- // The empty package, which holds all top level types without given packages.
- final object EmptyPackage extends ModuleSymbol(RootClass, NoPosition, nme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
+ class EmptyPackage extends ModuleSymbol(RootClass, NoPosition, nme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
override def isEmptyPackage = true
}
- final object EmptyPackageClass extends PackageClassSymbol(RootClass, NoPosition, tpnme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
+
+ // The empty package, which holds all top level types without given packages.
+ lazy val EmptyPackage = new EmptyPackage
+
+ class EmptyPackageClass extends PackageClassSymbol(RootClass, NoPosition, tpnme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
override def isEffectiveRoot = true
override def isEmptyPackageClass = true
+ override def sourceModule = EmptyPackage
}
+
+ lazy val EmptyPackageClass = new EmptyPackageClass
}
}
diff --git a/src/reflect/scala/reflect/internal/MissingRequirementError.scala b/src/reflect/scala/reflect/internal/MissingRequirementError.scala
index 48203caa83..66dbf535d7 100644
--- a/src/reflect/scala/reflect/internal/MissingRequirementError.scala
+++ b/src/reflect/scala/reflect/internal/MissingRequirementError.scala
@@ -3,7 +3,8 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
class MissingRequirementError private (msg: String) extends FatalError(msg) {
diff --git a/src/reflect/scala/reflect/internal/Mode.scala b/src/reflect/scala/reflect/internal/Mode.scala
new file mode 100644
index 0000000000..557ec9c162
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Mode.scala
@@ -0,0 +1,141 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala
+package reflect
+package internal
+
+import scala.language.implicitConversions
+
+object Mode {
+ private implicit def liftIntBitsToMode(bits: Int): Mode = apply(bits)
+ def apply(bits: Int): Mode = new Mode(bits)
+
+ /** NOmode, EXPRmode and PATTERNmode are mutually exclusive.
+ */
+ final val NOmode: Mode = 0x000
+ final val EXPRmode: Mode = 0x001
+ final val PATTERNmode: Mode = 0x002
+
+ /** TYPEmode needs a comment. <-- XXX.
+ */
+ final val TYPEmode: Mode = 0x004
+
+ /** SCCmode is orthogonal to above. When set we are
+ * in the this or super constructor call of a constructor.
+ */
+ final val SCCmode: Mode = 0x008
+
+ /** FUNmode is orthogonal to above.
+ * When set we are looking for a method or constructor.
+ */
+ final val FUNmode: Mode = 0x010
+
+ /** POLYmode is orthogonal to above.
+ * When set expression types can be polymorphic.
+ */
+ final val POLYmode: Mode = 0x020
+
+ /** QUALmode is orthogonal to above. When set
+ * expressions may be packages and Java statics modules.
+ */
+ final val QUALmode: Mode = 0x040
+
+ /** TAPPmode is set for the function/type constructor
+ * part of a type application. When set we do not decompose PolyTypes.
+ */
+ final val TAPPmode: Mode = 0x080
+
+ /** LHSmode is set for the left-hand side of an assignment.
+ */
+ final val LHSmode: Mode = 0x400
+
+ /** BYVALmode is set when we are typing an expression
+ * that occurs in a by-value position. An expression e1 is in by-value
+ * position within expression e2 iff it will be reduced to a value at that
+ * position during the evaluation of e2. Examples are by-value function
+ * arguments or the conditional of an if-then-else clause.
+ * This mode has been added to support continuations.
+ */
+ final val BYVALmode: Mode = 0x8000
+
+ /** TYPEPATmode is set when we are typing a type in a pattern.
+ */
+ final val TYPEPATmode: Mode = 0x10000
+
+ private val StickyModes: Mode = EXPRmode | PATTERNmode | TYPEmode
+ private val StickyModesForFun: Mode = StickyModes | SCCmode
+ final val MonoQualifierModes: Mode = EXPRmode | QUALmode
+ final val PolyQualifierModes: Mode = EXPRmode | QUALmode | POLYmode
+ final val OperatorModes: Mode = EXPRmode | POLYmode | TAPPmode | FUNmode
+
+ /** Translates a mask of mode flags into something readable.
+ */
+ private val modeNameMap = Map[Int, String]( // TODO why duplicate the bitmasks here, rather than just referring to this.EXPRmode etc?
+ (1 << 0) -> "EXPRmode",
+ (1 << 1) -> "PATTERNmode",
+ (1 << 2) -> "TYPEmode",
+ (1 << 3) -> "SCCmode",
+ (1 << 4) -> "FUNmode",
+ (1 << 5) -> "POLYmode",
+ (1 << 6) -> "QUALmode",
+ (1 << 7) -> "TAPPmode",
+ (1 << 8) -> "<>", // formerly SUPERCONSTRmode
+ (1 << 9) -> "<>", // formerly SNDTRYmode
+ (1 << 10) -> "LHSmode",
+ (1 << 11) -> "<>",
+ (1 << 12) -> "<>", // formerly STARmode
+ (1 << 13) -> "<>", // formerly ALTmode
+ (1 << 14) -> "<>", // formerly HKmode
+ (1 << 15) -> "BYVALmode",
+ (1 << 16) -> "TYPEPATmode"
+ ).map({ case (k, v) => Mode(k) -> v })
+}
+import Mode._
+
+final class Mode private (val bits: Int) extends AnyVal {
+ def &(other: Mode): Mode = new Mode(bits & other.bits)
+ def |(other: Mode): Mode = new Mode(bits | other.bits)
+ def &~(other: Mode): Mode = new Mode(bits & ~(other.bits))
+
+ def onlyTypePat = this & TYPEPATmode
+ def onlySticky = this & Mode.StickyModes
+ def forFunMode = this & Mode.StickyModesForFun | FUNmode | POLYmode | BYVALmode
+ def forTypeMode = if (typingPatternOrTypePat) TYPEmode | TYPEPATmode else TYPEmode
+
+ def inAll(required: Mode) = (this & required) == required
+ def inAny(required: Mode) = (this & required) != NOmode
+ def inNone(prohibited: Mode) = (this & prohibited) == NOmode
+
+ /** True if this mode matches every mode in the 'all' Mode,
+ * and no modes in the 'none' Mode.
+ */
+ def in(all: Mode = NOmode, none: Mode = NOmode) = inAll(all) && inNone(none)
+
+ def inByValMode = inAll(BYVALmode)
+ def inExprMode = inAll(EXPRmode)
+ def inFunMode = inAll(FUNmode)
+ def inPatternMode = inAll(PATTERNmode)
+ def inPolyMode = inAll(POLYmode)
+ def inQualMode = inAll(QUALmode)
+ def inSccMode = inAll(SCCmode)
+ def inTappMode = inAll(TAPPmode)
+ def inTypeMode = inAll(TYPEmode)
+
+ def typingExprByValue = inAll(EXPRmode | BYVALmode)
+ def typingExprFun = inAll(EXPRmode | FUNmode)
+ def typingExprNotFun = in(all = EXPRmode, none = FUNmode)
+ def typingExprNotFunNotLhs = in(all = EXPRmode, none = FUNmode | LHSmode)
+ def typingExprNotLhs = in(all = EXPRmode, none = LHSmode)
+ def typingExprNotValue = in(all = EXPRmode, none = BYVALmode)
+ def typingMonoExprByValue = in(all = EXPRmode | BYVALmode, none = POLYmode)
+ def typingConstructorPattern = inAll(PATTERNmode | FUNmode)
+ def typingPatternNotConstructor = in(all = PATTERNmode, none = FUNmode)
+ def typingPatternOrTypePat = inAny(PATTERNmode | TYPEPATmode)
+
+ override def toString =
+ if (this == NOmode) "NOmode"
+ else (modeNameMap filterKeys inAll).values.toList.sorted mkString "-"
+}
diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala
index c78ba72dfb..b50f324074 100644
--- a/src/reflect/scala/reflect/internal/Names.scala
+++ b/src/reflect/scala/reflect/internal/Names.scala
@@ -3,35 +3,33 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
import scala.io.Codec
import java.security.MessageDigest
import scala.language.implicitConversions
-trait LowPriorityNames {
- self: Names =>
-
- implicit def nameToNameOps(name: Name): NameOps[Name] = new NameOps[Name](name)
-}
-
-/** The class Names ...
- *
- * @author Martin Odersky
- * @version 1.0, 05/02/2005
- */
-trait Names extends api.Names with LowPriorityNames {
- implicit def promoteTermNamesAsNecessary(name: Name): TermName = name.toTermName
-
-// Operations -------------------------------------------------------------
-
+trait Names extends api.Names {
private final val HASH_SIZE = 0x8000
private final val HASH_MASK = 0x7FFF
private final val NAME_SIZE = 0x20000
final val nameDebug = false
+ // Ideally we would just synchronize unconditionally and let HotSpot's Biased Locking
+ // kick in in the compiler universe, where access to the lock is single threaded. But,
+ // objects created in the first 4seconds of the JVM startup aren't eligible for biased
+ // locking.
+ //
+ // We might also be able to accept the performance hit, but we don't have tools to
+ // detect performance regressions.
+ //
+ // Discussion: https://groups.google.com/forum/#!search/biased$20scala-internals/scala-internals/0cYB7SkJ-nM/47MLhsgw8jwJ
+ protected def synchronizeNames: Boolean = false
+ private val nameLock: Object = new Object
+
/** Memory to store all names sequentially. */
var chrs: Array[Char] = new Array[Char](NAME_SIZE)
private var nc = 0
@@ -42,14 +40,17 @@ trait Names extends api.Names with LowPriorityNames {
/** Hashtable for finding type names quickly. */
private val typeHashtable = new Array[TypeName](HASH_SIZE)
- /** The hashcode of a name. */
+ /**
+ * The hashcode of a name depends on the first, the last and the middle character,
+ * and the length of the 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;
+ else 0
/** Is (the ASCII representation of) name at given index equal to
* cs[offset..offset+len-1]?
@@ -57,7 +58,7 @@ trait Names extends api.Names with LowPriorityNames {
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 += 1
i == len
}
@@ -78,65 +79,101 @@ trait Names extends api.Names with LowPriorityNames {
}
/** Create a term name from the characters in cs[offset..offset+len-1]. */
- def newTermName(cs: Array[Char], offset: Int, len: Int): TermName =
+ final 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)
+ final def newTermName(cs: Array[Char]): TermName = newTermName(cs, 0, cs.length)
+
+ final 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.)
+ *
+ * @param len0 the length of the name. Negative lengths result in empty names.
*/
- 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)
+ final def newTermName(cs: Array[Char], offset: Int, len0: Int, cachedString: String): TermName = {
+ def body = {
+ require(offset >= 0, "offset must be non-negative, got " + offset)
+ val len = math.max(len0, 0)
+ 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.
+ var startIndex = 0
+ if (cs == chrs) {
+ // Optimize for subName, the new name is already stored in chrs
+ startIndex = offset
+ } else {
+ startIndex = nc
+ enterChars(cs, offset, len)
+ }
+ val next = termHashtable(h)
+ val termName =
+ if (cachedString ne null) new TermName_S(startIndex, len, next, cachedString)
+ else new TermName_R(startIndex, len, next)
+ // Add the new termName to the hashtable only after it's been fully constructed
+ termHashtable(h) = termName
+ termName
+ }
}
+ if (synchronizeNames) nameLock.synchronized(body) else body
}
- protected def newTypeName(cs: Array[Char], offset: Int, len: Int, cachedString: String): TypeName =
+
+ final def newTypeName(cs: Array[Char], offset: Int, len: Int, cachedString: String): TypeName =
newTermName(cs, offset, len, cachedString).toTypeName
/** Create a term name from string. */
+ @deprecatedOverriding("To synchronize, use `override def synchronizeNames = true`", "2.11.0") // overriden in https://github.com/scala-ide/scala-ide/blob/master/org.scala-ide.sdt.core/src/scala/tools/eclipse/ScalaPresentationCompiler.scala
def newTermName(s: String): TermName = newTermName(s.toCharArray(), 0, s.length(), null)
/** Create a type name from string. */
+ @deprecatedOverriding("To synchronize, use `override def synchronizeNames = true`", "2.11.0") // overriden in https://github.com/scala-ide/scala-ide/blob/master/org.scala-ide.sdt.core/src/scala/tools/eclipse/ScalaPresentationCompiler.scala
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 = {
+ final 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 =
+ final def newTermNameCached(s: String): TermName =
newTermName(s.toCharArray(), 0, s.length(), cachedString = s)
- def newTypeNameCached(s: String): TypeName =
+ final 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 =
+ final 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 =
+ final 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)
+ /**
+ * Used by the GenBCode backend to lookup type names that are known to already exist. This method
+ * might be invoked in a multi-threaded setting. Invoking newTypeName instead might be unsafe.
+ *
+ * can-multi-thread: names are added to the hash tables only after they are fully constructed.
+ */
+ final def lookupTypeName(cs: Array[Char]): TypeName = {
+ val hash = hashValue(cs, 0, cs.length) & HASH_MASK
+ var typeName = typeHashtable(hash)
+
+ while ((typeName ne null) && (typeName.length != cs.length || !equals(typeName.start, cs, 0, cs.length))) {
+ typeName = typeName.next
+ }
+ assert(typeName != null, s"TypeName ${new String(cs)} not yet created.")
+ typeName
+ }
// Classes ----------------------------------------------------------------------
@@ -186,28 +223,26 @@ trait Names extends api.Names with LowPriorityNames {
scala.compat.Platform.arraycopy(chrs, index, cs, offset, len)
/** @return the ascii representation of this name */
- final def toChars: Array[Char] = {
+ final def toChars: Array[Char] = { // used by ide
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)
- scala.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)
+ /** @return true if the string value of this name is equal
+ * to the string value of the given name or String.
+ */
+ def string_==(that: Name): Boolean = (that ne null) && (toString == that.toString)
+ def string_==(that: String): Boolean = (that ne null) && (toString == that)
+
+ /****
+ * This has been quite useful to find places where people are comparing
+ * a TermName and a TypeName, or a Name and a String.
+
+ override def equals(other: Any) = paranoidEquals(other)
private def paranoidEquals(other: Any): Boolean = {
val cmp = this eq other.asInstanceOf[AnyRef]
if (cmp || !nameDebug)
@@ -215,7 +250,7 @@ trait Names extends api.Names with LowPriorityNames {
other match {
case x: String =>
- Console.println("Compared " + debugString + " and String '" + x + "'")
+ Console.println(s"Compared $debugString and String '$x'")
case x: Name =>
if (this.isTermName != x.isTermName) {
val panic = this.toTermName == x.toTermName
@@ -228,6 +263,7 @@ trait Names extends api.Names with LowPriorityNames {
}
false
}
+ ****/
/** @return the i'th Char of this name */
final def charAt(i: Int): Char = chrs(index + i)
@@ -235,14 +271,14 @@ trait Names extends api.Names with LowPriorityNames {
/** @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 */
+ /** @return the index of first occurrence of s 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 ...
+ * @param start the index from which to search
* @return the index of the first occurrence of c
*/
final def pos(c: Char, start: Int): Int = {
@@ -255,7 +291,7 @@ trait Names extends api.Names with LowPriorityNames {
* in this name from start, length if not found.
*
* @param s the string
- * @param start ...
+ * @param start the index from which to search
* @return the index of the first occurrence of s
*/
final def pos(s: String, start: Int): Int = {
@@ -279,13 +315,11 @@ trait Names extends api.Names with LowPriorityNames {
*/
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 ...
+ * @param start the index from which to search
* @return the index of the last occurrence of c
*/
final def lastPos(c: Char, start: Int): Int = {
@@ -294,26 +328,6 @@ trait Names extends api.Names with LowPriorityNames {
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)
@@ -322,7 +336,14 @@ trait Names extends api.Names with LowPriorityNames {
var i = 0
while (i < prefix.length && start + i < len &&
chrs(index + start + i) == chrs(prefix.start + i))
- i += 1;
+ i += 1
+ i == prefix.length
+ }
+ final def startsWith(prefix: String, start: Int): Boolean = {
+ var i = 0
+ while (i < prefix.length && start + i < len &&
+ chrs(index + start + i) == prefix.charAt(i))
+ i += 1
i == prefix.length
}
@@ -334,7 +355,14 @@ trait Names extends api.Names with LowPriorityNames {
var i = 1
while (i <= suffix.length && i <= end &&
chrs(index + end - i) == chrs(suffix.start + suffix.length - i))
- i += 1;
+ i += 1
+ i > suffix.length
+ }
+ final def endsWith(suffix: String, end: Int): Boolean = {
+ var i = 1
+ while (i <= suffix.length && i <= end &&
+ chrs(index + end - i) == suffix.charAt(suffix.length - i))
+ i += 1
i > suffix.length
}
@@ -362,20 +390,22 @@ trait Names extends api.Names with LowPriorityNames {
final def startChar: Char = this charAt 0
final def endChar: Char = this charAt len - 1
final def startsWith(char: Char): Boolean = len > 0 && startChar == char
- final def startsWith(name: String): Boolean = startsWith(newTermName(name))
+ final def startsWith(name: String): Boolean = startsWith(name, 0)
final def endsWith(char: Char): Boolean = len > 0 && endChar == char
- final def endsWith(name: String): Boolean = endsWith(newTermName(name))
+ final def endsWith(name: String): Boolean = endsWith(name, len)
- 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)
+ /** Rewrite the confusing failure indication via result == length to
+ * the normal failure indication via result == -1.
+ */
+ private def fixIndexOf(idx: Int): Int = if (idx == length) -1 else idx
+
+ def indexOf(ch: Char) = fixIndexOf(pos(ch))
+ def indexOf(ch: Char, fromIndex: Int) = fixIndexOf(pos(ch, fromIndex))
+ def indexOf(s: String) = fixIndexOf(pos(s))
+
+ /** The lastPos methods already return -1 on failure. */
+ def lastIndexOf(ch: Char): Int = lastPos(ch)
+ def lastIndexOf(s: String): Int = toString lastIndexOf s
/** Replace all occurrences of `from` by `to` in
* name; result is always a term name.
@@ -421,27 +451,44 @@ trait Names extends api.Names with LowPriorityNames {
}
/** 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 append(ch: Char) = newName(toString + ch)
+ def append(suffix: String) = newName(toString + suffix)
+ def append(suffix: Name) = newName(toString + suffix)
+ def append(separator: Char, suffix: Name) = newName(toString + separator + suffix)
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 isOperatorName: Boolean = decode != toString // used by ide
def longString: String = nameKind + " " + decode
def debugString = { val s = decode ; if (isTypeName) s + "!" else s }
}
+ implicit def AnyNameOps(name: Name): NameOps[Name] = new NameOps(name)
implicit def TermNameOps(name: TermName): NameOps[TermName] = new NameOps(name)
implicit def TypeNameOps(name: TypeName): NameOps[TypeName] = new NameOps(name)
+ /** FIXME: This is a good example of something which is pure "value class" but cannot
+ * reap the benefits because an (unused) $outer pointer so it is not single-field.
+ */
final class NameOps[T <: Name](name: T) {
- def stripSuffix(suffix: Name): T = if (name endsWith suffix) dropRight(suffix.length) else name
- def dropRight(n: Int): T = name.subName(0, name.length - n).asInstanceOf[T]
- def drop(n: Int): T = name.subName(n, name.length).asInstanceOf[T]
- def nonEmpty: Boolean = name.length > 0
+ import NameTransformer._
+ def stripSuffix(suffix: String): T = if (name endsWith suffix) dropRight(suffix.length) else name // OPT avoid creating a Name with `suffix`
+ def stripSuffix(suffix: Name): T = if (name endsWith suffix) dropRight(suffix.length) else name
+ def take(n: Int): T = name.subName(0, n).asInstanceOf[T]
+ def drop(n: Int): T = name.subName(n, name.length).asInstanceOf[T]
+ def dropRight(n: Int): T = name.subName(0, name.length - n).asInstanceOf[T]
+ def dropLocal: TermName = name.toTermName stripSuffix LOCAL_SUFFIX_STRING
+ def dropSetter: TermName = name.toTermName stripSuffix SETTER_SUFFIX_STRING
+ def dropModule: T = this stripSuffix MODULE_SUFFIX_STRING
+ def localName: TermName = getterName append LOCAL_SUFFIX_STRING
+ def setterName: TermName = getterName append SETTER_SUFFIX_STRING
+ def getterName: TermName = dropTraitSetterSeparator.dropSetter.dropLocal
+
+ private def dropTraitSetterSeparator: TermName =
+ name indexOf TRAIT_SETTER_SEPARATOR_STRING match {
+ case -1 => name.toTermName
+ case idx => name.toTermName drop idx drop TRAIT_SETTER_SEPARATOR_STRING.length
+ }
}
implicit val NameTag = ClassTag[Name](classOf[Name])
@@ -462,42 +509,49 @@ trait Names extends api.Names with LowPriorityNames {
/** 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)
+ private final class TermName_S(index0: Int, len0: Int, next0: TermName, override val toString: String) extends TermName(index0, len0, next0) {
+ protected def createCompanionName(next: TypeName): TypeName = new TypeName_S(index, len, next, 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)
+ private final class TypeName_S(index0: Int, len0: Int, next0: TypeName, override val toString: String) extends TypeName(index0, len0, next0) {
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)
+ private final class TermName_R(index0: Int, len0: Int, next0: TermName) extends TermName(index0, len0, next0) {
+ protected def createCompanionName(next: TypeName): TypeName = new TypeName_R(index, len, next)
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)
+ private final class TypeName_R(index0: Int, len0: Int, next0: TypeName) extends TypeName(index0, len0, next0) {
override def toString = new String(chrs, index, len)
}
- sealed abstract class TermName(index0: Int, len0: Int, hash: Int) extends Name(index0, len0) {
+ // SYNCNOTE: caller to constructor must synchronize if `synchronizeNames` is enabled
+ sealed abstract class TermName(index0: Int, len0: Int, val next: TermName) extends Name(index0, len0) with TermNameApi {
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 body = {
+ // Re-computing the hash saves a field for storing it in the TermName
+ 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 {
+ val next = typeHashtable(h)
+ val typeName = createCompanionName(next)
+ // Add the new typeName to the hashtable only after it's been fully constructed
+ typeHashtable(h) = typeName
+ typeName
+ }
+ }
+ if (synchronizeNames) nameLock.synchronized(body) else body
}
def newName(str: String): TermName = newTermName(str)
def companionName: TypeName = toTypeName
@@ -505,27 +559,35 @@ trait Names extends api.Names with LowPriorityNames {
newTermName(chrs, start + from, to - from)
def nameKind = "term"
- protected def createCompanionName(h: Int): TypeName
+ /** SYNCNOTE: caller must synchronize if `synchronizeNames` is enabled */
+ protected def createCompanionName(next: TypeName): TypeName
}
implicit val TermNameTag = ClassTag[TermName](classOf[TermName])
- sealed abstract class TypeName(index0: Int, len0: Int, hash: Int) extends Name(index0, len0) {
+ object TermName extends TermNameExtractor {
+ def apply(s: String) = newTermName(s)
+ def unapply(name: TermName): Option[String] = Some(name.toString)
+ }
+
+ sealed abstract class TypeName(index0: Int, len0: Int, val next: TypeName) extends Name(index0, len0) with TypeNameApi {
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 body = {
+ // Re-computing the hash saves a field for storing it in the TypeName
+ val h = hashValue(chrs, index, len) & HASH_MASK
+ var n = termHashtable(h)
+ while ((n ne null) && n.start != index)
+ n = n.next
+
+ assert (n ne null, s"TypeName $this is missing its correspondent")
+ n
+ }
+ if (synchronizeNames) nameLock.synchronized(body) else body
}
def toTypeName: TypeName = this
def newName(str: String): TypeName = newTypeName(str)
@@ -535,8 +597,12 @@ trait Names extends api.Names with LowPriorityNames {
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])
+
+ object TypeName extends TypeNameExtractor {
+ def apply(s: String) = newTypeName(s)
+ def unapply(name: TypeName): Option[String] = Some(name.toString)
+ }
}
diff --git a/src/reflect/scala/reflect/internal/Phase.scala b/src/reflect/scala/reflect/internal/Phase.scala
index c0f4232724..1ecc202a07 100644
--- a/src/reflect/scala/reflect/internal/Phase.scala
+++ b/src/reflect/scala/reflect/internal/Phase.scala
@@ -3,7 +3,8 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
abstract class Phase(val prev: Phase) {
@@ -25,11 +26,14 @@ abstract class Phase(val prev: Phase) {
)
def flagMask: Long = fmask
- private var nx: Phase = this
+ private var nx: Phase = NoPhase
- def next: Phase = nx
+ // does anyone rely on next == this for terminus?
+ def next: Phase = if (nx eq NoPhase) this else nx
def hasNext = next != this
- def iterator = Iterator.iterate(this)(_.next) takeWhile (p => p.next != p)
+ // this definition excludes the terminal phase
+ //def iterator = Iterator.iterate(this)(_.nx) takeWhile (p => p.next != p)
+ def iterator = Iterator.iterate(this)(_.nx) takeWhile (_ ne NoPhase)
def name: String
def description: String = name
diff --git a/src/reflect/scala/reflect/internal/Positions.scala b/src/reflect/scala/reflect/internal/Positions.scala
index faa161d6b1..01fba1efc1 100644
--- a/src/reflect/scala/reflect/internal/Positions.scala
+++ b/src/reflect/scala/reflect/internal/Positions.scala
@@ -1,34 +1,274 @@
-package scala.reflect
+package scala
+package reflect
package internal
+import util._
+import scala.collection.mutable.ListBuffer
+
+/** Handling range positions
+ * atPos, the main method in this trait, will add positions to a tree,
+ * and will ensure the following properties:
+ *
+ * 1. All nodes between the root of the tree and nodes that already have positions
+ * will be assigned positions.
+ * 2. No node which already has a position will be assigned a different range; however
+ * a RangePosition might become a TransparentPosition.
+ * 3. The position of each assigned node includes the positions of each of its children.
+ * 4. The positions of all solid descendants of children of an assigned node
+ * are mutually non-overlapping.
+ *
+ * Here, the solid descendant of a node are:
+ *
+ * If the node has a TransparentPosition, the solid descendants of all its children
+ * Otherwise, the singleton consisting of the node itself.
+ */
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])
+ def inform(msg: String): Unit
+
+ def useOffsetPositions: Boolean = true
+
/** 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 that is either focused or not.
*/
- def wrappingPos(default: Position, trees: List[Tree]) = wrappingPos(default, trees, true)
- def wrappingPos(default: Position, trees: List[Tree], focus: Boolean): Position = default
+ def wrappingPos(default: Position, trees: List[Tree]): Position = wrappingPos(default, trees, focus = true)
+ def wrappingPos(default: Position, trees: List[Tree], focus: Boolean): Position = {
+ if (useOffsetPositions) default else {
+ val ranged = trees filter (_.pos.isRange)
+ if (ranged.isEmpty) if (focus) default.focus else default
+ else Position.range(default.source, (ranged map (_.pos.start)).min, default.point, (ranged map (_.pos.end)).max)
+ }
+ }
/** 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 some of 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
+ def wrappingPos(trees: List[Tree]): Position = {
+ val headpos = trees.head.pos
+ if (useOffsetPositions || !headpos.isDefined) headpos
+ else wrappingPos(headpos, trees)
+ }
/** Ensure that given tree has no positions that overlap with
* any of the positions of `others`. This is done by
* shortening the range, assigning TransparentPositions
* to some of the nodes in `tree` or focusing on the position.
*/
- def ensureNonOverlapping(tree: Tree, others: List[Tree]){ ensureNonOverlapping(tree, others, true) }
- def ensureNonOverlapping(tree: Tree, others: List[Tree], focus: Boolean) {}
+ def ensureNonOverlapping(tree: Tree, others: List[Tree]){ ensureNonOverlapping(tree, others, focus = true) }
+ def ensureNonOverlapping(tree: Tree, others: List[Tree], focus: Boolean) {
+ if (useOffsetPositions) return
+
+ def isOverlapping(pos: Position) =
+ pos.isRange && (others exists (pos overlaps _.pos))
+
+ if (isOverlapping(tree.pos)) {
+ val children = tree.children
+ children foreach (ensureNonOverlapping(_, others, focus))
+ if (tree.pos.isOpaqueRange) {
+ val wpos = wrappingPos(tree.pos, children, focus)
+ tree setPos (if (isOverlapping(wpos)) tree.pos.makeTransparent else wpos)
+ }
+ }
+ }
+
+ def rangePos(source: SourceFile, start: Int, point: Int, end: Int): Position =
+ if (useOffsetPositions) Position.offset(source, point)
+ else Position.range(source, start, point, end)
+
+ def validatePositions(tree: Tree) {
+ if (useOffsetPositions) return
+
+ def reportTree(prefix : String, tree : Tree) {
+ val source = if (tree.pos.isDefined) tree.pos.source else ""
+ inform("== "+prefix+" tree ["+tree.id+"] of type "+tree.productPrefix+" at "+tree.pos.show+source)
+ inform("")
+ inform(treeStatus(tree))
+ inform("")
+ }
+
+ def positionError(msg: String)(body : => Unit) {
+ inform("======= Position error\n" + msg)
+ body
+ inform("\nWhile validating #" + tree.id)
+ inform(treeStatus(tree))
+ inform("\nChildren:")
+ tree.children map (t => " " + treeStatus(t, tree)) foreach inform
+ inform("=======")
+ throw new ValidateException(msg)
+ }
+
+ def validate(tree: Tree, encltree: Tree): Unit = {
+
+ if (!tree.isEmpty && tree.canHaveAttrs) {
+ if (settings.Yposdebug && (settings.verbose || settings.Yrangepos))
+ println("[%10s] %s".format("validate", treeStatus(tree, encltree)))
+
+ if (!tree.pos.isDefined)
+ positionError("Unpositioned tree #"+tree.id) {
+ inform("%15s %s".format("unpositioned", treeStatus(tree, encltree)))
+ inform("%15s %s".format("enclosing", treeStatus(encltree)))
+ encltree.children foreach (t => inform("%15s %s".format("sibling", treeStatus(t, encltree))))
+ }
+ if (tree.pos.isRange) {
+ if (!encltree.pos.isRange)
+ positionError("Synthetic tree ["+encltree.id+"] contains nonsynthetic tree ["+tree.id+"]") {
+ reportTree("Enclosing", encltree)
+ reportTree("Enclosed", tree)
+ }
+ if (!(encltree.pos includes tree.pos))
+ positionError("Enclosing tree ["+encltree.id+"] does not include tree ["+tree.id+"]") {
+ reportTree("Enclosing", encltree)
+ reportTree("Enclosed", tree)
+ }
+
+ findOverlapping(tree.children flatMap solidDescendants) match {
+ case List() => ;
+ case xs => {
+ positionError("Overlapping trees "+xs.map { case (x, y) => (x.id, y.id) }.mkString("", ", ", "")) {
+ reportTree("Ancestor", tree)
+ for((x, y) <- xs) {
+ reportTree("First overlapping", x)
+ reportTree("Second overlapping", y)
+ }
+ }
+ }
+ }
+ }
+ for (ct <- tree.children flatMap solidDescendants) validate(ct, tree)
+ }
+ }
+
+ if (!isPastTyper)
+ validate(tree, tree)
+ }
+
+ def solidDescendants(tree: Tree): List[Tree] =
+ if (tree.pos.isTransparent) tree.children flatMap solidDescendants
+ else List(tree)
+
+ /** A free range from `lo` to `hi` */
+ private def free(lo: Int, hi: Int): Range =
+ Range(Position.range(null, lo, lo, hi), EmptyTree)
+
+ /** The maximal free range */
+ private lazy val maxFree: Range = free(0, Int.MaxValue)
+
+ /** A singleton list of a non-empty range from `lo` to `hi`, or else the empty List */
+ private def maybeFree(lo: Int, hi: Int) =
+ if (lo < hi) List(free(lo, hi))
+ else List()
+
+ /** Insert `pos` into ranges `rs` if possible;
+ * otherwise add conflicting trees to `conflicting`.
+ */
+ private def insert(rs: List[Range], t: Tree, conflicting: ListBuffer[Tree]): List[Range] = rs match {
+ case List() =>
+ assert(conflicting.nonEmpty)
+ rs
+ case r :: rs1 =>
+ assert(!t.pos.isTransparent)
+ if (r.isFree && (r.pos includes t.pos)) {
+// println("subdividing "+r+"/"+t.pos)
+ maybeFree(t.pos.end, r.pos.end) ::: List(Range(t.pos, t)) ::: maybeFree(r.pos.start, t.pos.start) ::: rs1
+ } else {
+ if (!r.isFree && (r.pos overlaps t.pos)) conflicting += r.tree
+ r :: insert(rs1, t, conflicting)
+ }
+ }
+
+ /** Replace elem `t` of `ts` by `replacement` list. */
+ private def replace(ts: List[Tree], t: Tree, replacement: List[Tree]): List[Tree] =
+ if (ts.head == t) replacement ::: ts.tail
+ else ts.head :: replace(ts.tail, t, replacement)
+
+ /** Does given list of trees have mutually non-overlapping positions?
+ * pre: None of the trees is transparent
+ */
+ def findOverlapping(cts: List[Tree]): List[(Tree, Tree)] = {
+ var ranges = List(maxFree)
+ for (ct <- cts) {
+ if (ct.pos.isOpaqueRange) {
+ val conflicting = new ListBuffer[Tree]
+ ranges = insert(ranges, ct, conflicting)
+ if (conflicting.nonEmpty) return conflicting.toList map (t => (t, ct))
+ }
+ }
+ List()
+ }
+
+ /** Set position of all children of a node
+ * @param pos A target position.
+ * Uses the point of the position as the point of all positions it assigns.
+ * Uses the start of this position as an Offset position for unpositioed trees
+ * without children.
+ * @param trees The children to position. All children must be positionable.
+ */
+ private def setChildrenPos(pos: Position, trees: List[Tree]): Unit = try {
+ for (tree <- trees) {
+ if (!tree.isEmpty && tree.canHaveAttrs && tree.pos == NoPosition) {
+ val children = tree.children
+ if (children.isEmpty) {
+ tree setPos pos.focus
+ } else {
+ setChildrenPos(pos, children)
+ tree setPos wrappingPos(pos, children)
+ }
+ }
+ }
+ } catch {
+ case ex: Exception =>
+ println("error while set children pos "+pos+" of "+trees)
+ throw ex
+ }
+
+
+ class ValidateException(msg : String) extends Exception(msg)
+
+
+ /** A locator for trees with given positions.
+ * Given a position `pos`, locator.apply returns
+ * the smallest tree that encloses `pos`.
+ */
+ class Locator(pos: Position) extends Traverser {
+ var last: Tree = _
+ def locateIn(root: Tree): Tree = {
+ this.last = EmptyTree
+ traverse(root)
+ this.last
+ }
+ protected def isEligible(t: Tree) = !t.pos.isTransparent
+ override def traverse(t: Tree) {
+ t match {
+ case tt : TypeTree if tt.original != null && (tt.pos includes tt.original.pos) =>
+ traverse(tt.original)
+ case _ =>
+ if (t.pos includes pos) {
+ if (isEligible(t)) last = t
+ super.traverse(t)
+ } else t match {
+ case mdef: MemberDef =>
+ traverseTrees(mdef.mods.annotations)
+ case _ =>
+ }
+ }
+ }
+ }
+
+ case class Range(pos: Position, tree: Tree) {
+ def isFree = tree == EmptyTree
+ }
+
+ class TypedLocator(pos: Position) extends Locator(pos) {
+ override protected def isEligible(t: Tree) = super.isEligible(t) && t.tpe != null
+ }
trait PosAssigner extends Traverser {
var pos: Position
@@ -38,7 +278,7 @@ trait Positions extends api.Positions { self: SymbolTable =>
protected class DefaultPosAssigner extends PosAssigner {
var pos: Position = _
override def traverse(t: Tree) {
- if (t eq EmptyTree) ()
+ if (!t.canHaveAttrs) ()
else if (t.pos == NoPosition) {
t.setPos(pos)
super.traverse(t) // TODO: bug? shouldn't the traverse be outside of the if?
@@ -57,9 +297,25 @@ trait Positions extends api.Positions { self: SymbolTable =>
}
}
+ /** Position a tree.
+ * This means: Set position of a node and position all its unpositioned children.
+ */
def atPos[T <: Tree](pos: Position)(tree: T): T = {
- posAssigner.pos = pos
- posAssigner.traverse(tree)
- tree
+ if (useOffsetPositions || !pos.isOpaqueRange) {
+ posAssigner.pos = pos
+ posAssigner.traverse(tree)
+ tree
+ }
+ else {
+ if (!tree.isEmpty && tree.canHaveAttrs && tree.pos == NoPosition) {
+ tree.setPos(pos)
+ val children = tree.children
+ if (children.nonEmpty) {
+ if (children.tail.isEmpty) atPos(pos)(children.head)
+ else setChildrenPos(pos, children)
+ }
+ }
+ tree
+ }
}
-} \ No newline at end of file
+}
diff --git a/src/reflect/scala/reflect/internal/Precedence.scala b/src/reflect/scala/reflect/internal/Precedence.scala
new file mode 100644
index 0000000000..1430838b9d
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Precedence.scala
@@ -0,0 +1,38 @@
+package scala
+package reflect
+package internal
+
+import scala.annotation.switch
+import Chars._
+
+final class Precedence private (val level: Int) extends AnyVal with Ordered[Precedence] {
+ def compare(that: Precedence): Int = level compare that.level
+ override def toString = s"Precedence($level)"
+}
+
+
+object Precedence extends (Int => Precedence) {
+ private val ErrorName = "<error>"
+ private def isAssignmentOp(name: String) = name match {
+ case "!=" | "<=" | ">=" | "" => false
+ case _ => name.last == '=' && name.head != '=' && isOperatorPart(name.head)
+ }
+ private def firstChar(ch: Char): Precedence = apply((ch: @switch) match {
+ case '|' => 2
+ case '^' => 3
+ case '&' => 4
+ case '=' | '!' => 5
+ case '<' | '>' => 6
+ case ':' => 7
+ case '+' | '-' => 8
+ case '*' | '/' | '%' => 9
+ case _ => if (isScalaLetter(ch)) 1 else 10
+ })
+
+ def apply(level: Int): Precedence = new Precedence(level)
+ def apply(name: String): Precedence = name match {
+ case "" | ErrorName => this(-1)
+ case _ if isAssignmentOp(name) => this(0)
+ case _ => firstChar(name charAt 0)
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala
index 35cb749ede..fcc377ba32 100644
--- a/src/reflect/scala/reflect/internal/Printers.scala
+++ b/src/reflect/scala/reflect/internal/Printers.scala
@@ -5,7 +5,8 @@
// todo. we need to unify this prettyprinter with NodePrinters
-package scala.reflect
+package scala
+package reflect
package internal
import java.io.{ OutputStream, PrintWriter, StringWriter, Writer }
@@ -16,8 +17,6 @@ trait Printers extends api.Printers { 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
@@ -25,34 +24,35 @@ trait Printers extends api.Printers { self: SymbolTable =>
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)
+ def quotedName(name: Name): String = quotedName(name, decode = false)
+ def quotedName(name: String): String = quotedName(newTermName(name), decode = 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)
- }
+ val sym = tree.symbol
+ def qname = quotedName(name.dropLocal, decoded)
+ def qowner = quotedName(sym.owner.name.dropLocal, decoded)
+ def qsymbol = quotedName(sym.nameString)
+
+ if (sym == null || sym == NoSymbol)
+ qname
+ else if (sym.isErroneous)
+ s"<$qname: error>"
+ else if (sym.isMixinConstructor)
+ s"/*$qowner*/$qsymbol"
+ else
+ qsymbol
}
- def decodedSymName(tree: Tree, name: Name) = symNameInternal(tree, name, true)
- def symName(tree: Tree, name: Name) = symNameInternal(tree, name, false)
+ def decodedSymName(tree: Tree, name: Name) = symNameInternal(tree, name, decoded = true)
+ def symName(tree: Tree, name: Name) = symNameInternal(tree, name, decoded = 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 Select(qual, name) if name.isTermName => s"${backquotedPath(qual)}.${symName(t, name)}"
+ case Select(qual, name) if name.isTypeName => s"${backquotedPath(qual)}#${symName(t, name)}"
case Ident(name) => symName(t, name)
case _ => t.toString
}
@@ -65,16 +65,24 @@ trait Printers extends api.Printers { self: SymbolTable =>
printTypes = settings.printtypes.value
printIds = settings.uniqid.value
+ printOwners = settings.Yshowsymowners.value
printKinds = settings.Yshowsymkinds.value
printMirrors = false // typically there's no point to print mirrors inside the compiler, as there is only one mirror there
- protected def doPrintPositions = settings.Xprintpos.value
+ printPositions = settings.Xprintpos.value
def indent() = indentMargin += indentStep
def undent() = indentMargin -= indentStep
- def printPosition(tree: Tree) = if (doPrintPositions) print(tree.pos.show)
+ def printPosition(tree: Tree) =
+ if (printPositions) comment(print(tree.pos.show))
+
+ protected def printTypesInfo(tree: Tree) =
+ if (printTypes && tree.isTerm && tree.canHaveAttrs)
+ comment{
+ print("{", if (tree.tpe eq null) "<null>" else tree.tpe.toString, "}")
+ }
- def println() {
+ def println() = {
out.println()
while (indentMargin > indentString.length())
indentString += indentString
@@ -82,116 +90,237 @@ trait Printers extends api.Printers { self: SymbolTable =>
out.write(indentString, 0, indentMargin)
}
- def printSeq[a](ls: List[a])(printelem: a => Unit)(printsep: => Unit) {
+ def printSeq[a](ls: List[a])(printelem: a => Unit)(printsep: => Unit): 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 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) {
+ def printRow(ts: List[Tree], start: String, sep: String, end: String): Unit = {
print(start); printSeq(ts){print(_)}{print(sep)}; print(end)
}
- def printRow(ts: List[Tree], sep: String) { printRow(ts, "", sep, "") }
+ def printRow(ts: List[Tree], sep: String): Unit = printRow(ts, "", sep, "")
- def printTypeParams(ts: List[TypeDef]) {
- if (!ts.isEmpty) {
+ def printTypeParams(ts: List[TypeDef]): Unit =
+ if (ts.nonEmpty) {
print("["); printSeq(ts){ t =>
printAnnotations(t)
+ if (t.mods.hasFlag(CONTRAVARIANT)) {
+ print("-")
+ } else if (t.mods.hasFlag(COVARIANT)) {
+ print("+")
+ }
printParam(t)
}{print(", ")}; print("]")
}
- }
- def printLabelParams(ps: List[Ident]) {
+ def printLabelParams(ps: List[Ident]) = {
print("(")
printSeq(ps){printLabelParam}{print(", ")}
print(")")
}
- def printLabelParam(p: Ident) {
+ 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(")")
+ protected def parenthesize(condition: Boolean = true, open: String = "(", close: String = ")")(body: => Unit) = {
+ if (condition) print(open)
+ body
+ if (condition) print(close)
}
- def printParam(tree: Tree) {
+ protected val commentsRequired = false
+
+ protected def comment(body: => Unit) =
+ parenthesize(commentsRequired, "/*", "*/")(body)
+
+ protected def printImplicitInParamsList(vds: List[ValDef]) =
+ if (vds.nonEmpty) printFlags(vds.head.mods.flags & IMPLICIT, "")
+
+ def printValueParams(ts: List[ValDef], inParentheses: Boolean = true): Unit =
+ parenthesize(inParentheses){
+ printImplicitInParamsList(ts)
+ printSeq(ts){printParam}{print(", ")}
+ }
+
+ def printParam(tree: Tree) =
tree match {
- case ValDef(mods, name, tp, rhs) =>
+ case vd @ ValDef(mods, name, tp, rhs) =>
printPosition(tree)
- printAnnotations(tree)
+ printAnnotations(vd)
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) {
+ 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)
+ 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 printOpt(prefix: String, tree: Tree) = if (tree.nonEmpty) { 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 ""
+ 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
+ def printFlags(flags: Long, privateWithin: String) = {
+ val mask: Long = if (settings.debug) -1L else PrintableFlags
val s = flagsToString(flags & mask, privateWithin)
if (s != "") print(s + " ")
}
- def printAnnotations(tree: Tree) {
+ def printAnnotations(tree: MemberDef) = {
// SI-5885: by default this won't print annotations of not yet initialized symbols
val annots = tree.symbol.annotations match {
- case Nil => tree.asInstanceOf[MemberDef].mods.annotations
+ case Nil => tree.mods.annotations
case anns => anns
}
- annots foreach (annot => print("@"+annot+" "))
+ annots foreach (annot => print(s"@$annot "))
}
private var currentOwner: Symbol = NoSymbol
private var selectorType: Type = NoType
- def printTree(tree: Tree) {
+ protected def printPackageDef(tree: PackageDef, separator: String) = {
+ val PackageDef(packaged, stats) = tree
+ printAnnotations(tree)
+ print("package ", packaged); printColumn(stats, " {", separator, "}")
+ }
+
+ protected def printValDef(tree: ValDef, resultName: => String)(printTypeSignature: => Unit)(printRhs: => Unit) = {
+ val ValDef(mods, name, tp, rhs) = tree
+ printAnnotations(tree)
+ printModifiers(tree, mods)
+ print(if (mods.isMutable) "var " else "val ", resultName)
+ printTypeSignature
+ printRhs
+ }
+
+ protected def printDefDef(tree: DefDef, resultName: => String)(printTypeSignature: => Unit)(printRhs: => Unit) = {
+ val DefDef(mods, name, tparams, vparamss, tp, rhs) = tree
+ printAnnotations(tree)
+ printModifiers(tree, mods)
+ print("def " + resultName)
+ printTypeParams(tparams);
+ vparamss foreach {printValueParams(_)}
+ printTypeSignature
+ printRhs
+ }
+
+ protected def printTypeDef(tree: TypeDef, resultName: => String) = {
+ val TypeDef(mods, name, tparams, rhs) = tree
+ if (mods hasFlag (PARAM | DEFERRED)) {
+ printAnnotations(tree)
+ printModifiers(tree, mods)
+ print("type ")
+ printParam(tree)
+ } else {
+ printAnnotations(tree)
+ printModifiers(tree, mods)
+ print("type " + resultName)
+ printTypeParams(tparams)
+ printOpt(" = ", rhs)
+ }
+ }
+
+ protected def printImport(tree: Import, resSelect: => String) = {
+ val Import(expr, selectors) = tree
+ // Is this selector renaming a name (i.e, {name1 => name2})
+ def isNotRename(s: ImportSelector): Boolean =
+ s.name == nme.WILDCARD || s.name == s.rename
+
+ def selectorToString(s: ImportSelector): String = {
+ val from = quotedName(s.name)
+ if (isNotRename(s)) from
+ else from + "=>" + quotedName(s.rename)
+ }
+ print("import ", resSelect, ".")
+ selectors match {
+ case List(s) =>
+ // If there is just one selector and it is not renaming a name, no braces are needed
+ if (isNotRename(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("{", ", ", "}"))
+ }
+ }
+
+ protected def printCaseDef(tree: CaseDef) = {
+ val CaseDef(pat, guard, body) = tree
+ print("case ")
+ def patConstr(pat: Tree): Tree = pat match {
+ case Apply(fn, args) => patConstr(fn)
+ case _ => pat
+ }
+
+ print(pat); printOpt(" if ", guard)
+ print(" => ", body)
+ }
+
+ protected def printFunction(tree: Function)(printValueParams: => Unit) = {
+ val Function(vparams, body) = tree
+ print("(");
+ printValueParams
+ print(" => ", body, ")")
+ if (printIds && tree.symbol != null)
+ comment{
+ print("#" + tree.symbol.id)
+ }
+
+ if (printOwners && tree.symbol != null)
+ comment{
+ print("@" + tree.symbol.owner.id)
+ }
+ }
+
+ protected def printSuper(tree: Super, resultName: => String, checkSymbol: Boolean = true) = {
+ val Super(This(qual), mix) = tree
+ if (qual.nonEmpty || (checkSymbol && tree.symbol != NoSymbol)) print(resultName + ".")
+ print("super")
+ if (mix.nonEmpty) print(s"[$mix]")
+ }
+
+ protected def printThis(tree: This, resultName: => String) = {
+ val This(qual) = tree
+ if (qual.nonEmpty) print(resultName + ".")
+ print("this")
+ }
+
+ protected def printBlock(stats: List[Tree], expr: Tree) =
+ printColumn(stats ::: List(expr), "{", ";", "}")
+
+ def printTree(tree: Tree) = {
tree match {
case EmptyTree =>
print("<empty>")
- case ClassDef(mods, name, tparams, impl) =>
- printAnnotations(tree)
+ case cd @ ClassDef(mods, name, tparams, impl) =>
+ printAnnotations(cd)
printModifiers(tree, mods)
val word =
if (mods.isTrait) "trait"
@@ -202,85 +331,49 @@ trait Printers extends api.Printers { self: SymbolTable =>
printTypeParams(tparams)
print(if (mods.isDeferred) " <: " else " extends ", impl)
- case PackageDef(packaged, stats) =>
- printAnnotations(tree)
- print("package ", packaged); printColumn(stats, " {", ";", "}")
+ case pd @ PackageDef(packaged, stats) =>
+ printPackageDef(pd, ";")
- case ModuleDef(mods, name, impl) =>
- printAnnotations(tree)
- printModifiers(tree, mods);
+ case md @ ModuleDef(mods, name, impl) =>
+ printAnnotations(md)
+ 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 vd @ ValDef(mods, name, tp, rhs) =>
+ printValDef(vd, 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 dd @ DefDef(mods, name, tparams, vparamss, tp, rhs) =>
+ printDefDef(dd, symName(tree, name))(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 td @ TypeDef(mods, name, tparams, rhs) =>
+ printTypeDef(td, symName(tree, name))
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 imp @ Import(expr, _) =>
+ printImport(imp, backquotedPath(expr))
- case Template(parents, self, body) =>
+ 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 (body.nonEmpty) {
if (self.name != nme.WILDCARD) {
print(" { ", self.name); printOpt(": ", self.tpt); print(" => ")
- } else if (!self.tpt.isEmpty) {
+ } else if (self.tpt.nonEmpty) {
print(" { _ : ", self.tpt, " => ")
} else {
print(" {")
}
printColumn(body, "", ";", "}")
}
-// }
currentOwner = currentOwner1
case Block(stats, expr) =>
- printColumn(stats ::: List(expr), "{", ";", "}")
+ printBlock(stats, expr)
case Match(selector, cases) =>
val selectorType1 = selectorType
@@ -288,18 +381,8 @@ trait Printers extends api.Printers { self: SymbolTable =>
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 cd @ CaseDef(pat, guard, body) =>
+ printCaseDef(cd)
case Alternative(trees) =>
printRow(trees, "(", "| ", ")")
@@ -316,9 +399,8 @@ trait Printers extends api.Printers { self: SymbolTable =>
case ArrayValue(elemtpt, trees) =>
print("Array[", elemtpt); printRow(trees, "]{", ", ", "}")
- case Function(vparams, body) =>
- print("("); printValueParams(vparams); print(" => ", body, ")")
- if (printIds && tree.symbol != null) print("#"+tree.symbol.id)
+ case f @ Function(vparams, body) =>
+ printFunction(f)(printValueParams(vparams))
case Assign(lhs, rhs) =>
print(lhs, " = ", rhs)
@@ -327,10 +409,10 @@ trait Printers extends api.Printers { self: SymbolTable =>
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
+ print("if (", cond, ")"); indent(); println()
+ print(thenp); undent()
+ if (elsep.nonEmpty) {
+ println(); print("else"); indent(); println(); print(elsep); undent()
}
case Return(expr) =>
@@ -338,7 +420,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
case Try(block, catches, finalizer) =>
print("try "); printBlock(block)
- if (!catches.isEmpty) printColumn(catches, " catch {", "", "}")
+ if (catches.nonEmpty) printColumn(catches, " catch {", "", "}")
printOpt(" finally ", finalizer)
case Throw(expr) =>
@@ -360,22 +442,18 @@ trait Printers extends api.Printers { self: SymbolTable =>
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 st @ Super(This(qual), mix) =>
+ printSuper(st, symName(tree, qual))
case Super(qual, mix) =>
print(qual, ".super")
- if (!mix.isEmpty)
+ if (mix.nonEmpty)
print("[" + mix + "]")
- case This(qual) =>
- if (!qual.isEmpty) print(symName(tree, qual) + ".")
- print("this")
+ case th @ This(qual) =>
+ printThis(th, symName(tree, qual))
- case Select(qual @ New(tpe), name) if (!settings.debug.value) =>
+ case Select(qual: New, name) if !settings.debug =>
print(qual)
case Select(qualifier, name) =>
@@ -389,7 +467,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
print(x.escapedStringValue)
case tt: TypeTree =>
- if ((tree.tpe eq null) || (doPrintPositions && tt.original != null)) {
+ if ((tree.tpe eq null) || (printPositions && 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) {
@@ -398,10 +476,10 @@ trait Printers extends api.Printers { self: SymbolTable =>
print(tree.tpe.toString)
}
- case Annotated(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), tree) =>
+ case an @ Annotated(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), tree) =>
def printAnnot() {
print("@", tpt)
- if (!args.isEmpty)
+ if (args.nonEmpty)
printRow(args, "(", ",", ")")
}
print(tree, if (tree.isType) " " else ": ")
@@ -420,24 +498,29 @@ trait Printers extends api.Printers { self: SymbolTable =>
print(tp); printRow(args, "[", ", ", "]")
case TypeBoundsTree(lo, hi) =>
- printOpt(" >: ", lo); printOpt(" <: ", hi)
+ // Avoid printing noisy empty typebounds everywhere
+ // Untyped empty bounds are not printed by printOpt,
+ // but after they are typed we have to exclude Nothing/Any.
+ if ((lo.tpe eq null) || !(lo.tpe =:= definitions.NothingTpe))
+ printOpt(" >: ", lo)
+
+ if ((hi.tpe eq null) || !(hi.tpe =:= definitions.AnyTpe))
+ printOpt(" <: ", hi)
case ExistentialTypeTree(tpt, whereClauses) =>
- print(tpt);
+ print(tpt)
printColumn(whereClauses, " forSome { ", ";", "}")
-// SelectFromArray is no longer visible in reflect.internal.
-// eliminated until we figure out what we will do with both Printers and
-// SelectFromArray.
-// case SelectFromArray(qualifier, name, _) =>
-// print(qualifier); print(".<arr>"); print(symName(tree, name))
+ // SelectFromArray is no longer visible in scala.reflect.internal.
+ // eliminated until we figure out what we will do with both Printers and
+ // SelectFromArray.
+ // case SelectFromArray(qualifier, name, _) =>
+ // print(qualifier); print(".<arr>"); print(symName(tree, name))
case tree =>
xprintTree(this, tree)
}
- if (printTypes && tree.isTerm && !tree.isEmpty) {
- print("{", if (tree.tpe eq null) "<null>" else tree.tpe.toString, "}")
- }
+ printTypesInfo(tree)
}
def print(args: Any*): Unit = args foreach {
@@ -451,10 +534,570 @@ trait Printers extends api.Printers { self: SymbolTable =>
}
}
+ // it's the printer for AST-based code generation
+ class CodePrinter(out: PrintWriter, printRootPkg: Boolean) extends TreePrinter(out) {
+ protected val parentsStack = scala.collection.mutable.Stack[Tree]()
+
+ protected def currentTree = if (parentsStack.nonEmpty) Some(parentsStack.top) else None
+
+ protected def currentParent = if (parentsStack.length > 1) Some(parentsStack(1)) else None
+
+ protected def printedName(name: Name, decoded: Boolean = true) = {
+ import Chars._
+ val decName = name.decoded
+ val bslash = '\\'
+ val brackets = List('[',']','(',')','{','}')
+
+ def addBackquotes(s: String) =
+ if (decoded && (decName.exists(ch => brackets.contains(ch) || isWhitespace(ch)) ||
+ (name.isOperatorName && decName.exists(isOperatorPart) && decName.exists(isScalaLetter) && !decName.contains(bslash))))
+ s"`$s`" else s
+
+ if (name == nme.CONSTRUCTOR) "this"
+ else addBackquotes(quotedName(name, decoded))
+ }
+
+ protected def isIntLitWithDecodedOp(qual: Tree, name: Name) = {
+ val qualIsIntLit = qual match {
+ case Literal(Constant(x: Int)) => true
+ case _ => false
+ }
+ qualIsIntLit && name.isOperatorName
+ }
+
+ override protected val commentsRequired = true
+
+ protected def needsParentheses(parent: Tree)(insideIf: Boolean = true, insideMatch: Boolean = true, insideTry: Boolean = true,
+ insideAnnotated: Boolean = true, insideBlock: Boolean = true, insideLabelDef: Boolean = true, insideAssign: Boolean = true) = {
+ parent match {
+ case _: If => insideIf
+ case _: Match => insideMatch
+ case _: Try => insideTry
+ case _: Annotated => insideAnnotated
+ case _: Block => insideBlock
+ case _: LabelDef => insideLabelDef
+ case _: Assign => insideAssign
+ case _ => false
+ }
+ }
+
+ protected def checkForBlank(cond: Boolean) = if (cond) " " else ""
+ protected def blankForOperatorName(name: Name) = checkForBlank(name.isOperatorName)
+ protected def blankForName(name: Name) = checkForBlank(name.isOperatorName || name.endsWith("_"))
+
+ protected def resolveSelect(t: Tree): String = {
+ t match {
+ // case for: 1) (if (a) b else c).meth1.meth2 or 2) 1 + 5 should be represented as (1).+(5)
+ case Select(qual, name) if (name.isTermName && needsParentheses(qual)(insideLabelDef = false)) || isIntLitWithDecodedOp(qual, name) => s"(${resolveSelect(qual)}).${printedName(name)}"
+ case Select(qual, name) if name.isTermName => s"${resolveSelect(qual)}.${printedName(name)}"
+ case Select(qual, name) if name.isTypeName => s"${resolveSelect(qual)}#${blankForOperatorName(name)}%${printedName(name)}"
+ case Ident(name) => printedName(name)
+ case _ => render(t, new CodePrinter(_, printRootPkg))
+ }
+ }
+
+ protected def emptyTree(tree: Tree) = tree match {
+ case EmptyTree | build.SyntacticEmptyTypeTree() => true
+ case _ => false
+ }
+
+ protected def originalTypeTrees(trees: List[Tree]) =
+ trees.filter(!emptyTree(_)) map {
+ case tt: TypeTree => tt.original
+ case tree => tree
+ }
+
+ val defaultClasses = List(tpnme.AnyRef)
+ val defaultTraitsForCase = List(tpnme.Product, tpnme.Serializable)
+ protected def removeDefaultTypesFromList(trees: List[Tree])(classesToRemove: List[Name] = defaultClasses)(traitsToRemove: List[Name]) = {
+ def removeDefaultTraitsFromList(trees: List[Tree], traitsToRemove: List[Name]): List[Tree] =
+ trees match {
+ case Nil => trees
+ case init :+ last => last match {
+ case Select(Ident(sc), name) if traitsToRemove.contains(name) && sc == nme.scala_ =>
+ removeDefaultTraitsFromList(init, traitsToRemove)
+ case _ => trees
+ }
+ }
+
+ removeDefaultTraitsFromList(removeDefaultClassesFromList(trees, classesToRemove), traitsToRemove)
+ }
+
+ protected def removeDefaultClassesFromList(trees: List[Tree], classesToRemove: List[Name] = defaultClasses) =
+ originalTypeTrees(trees) filter {
+ case Select(Ident(sc), name) => !(classesToRemove.contains(name) && sc == nme.scala_)
+ case _ => true
+ }
+
+ protected def syntheticToRemove(tree: Tree) =
+ tree match {
+ case _: ValDef | _: TypeDef => false // don't remove ValDef and TypeDef
+ case md: MemberDef if md.mods.isSynthetic => true
+ case _ => false
+ }
+
+ override def printOpt(prefix: String, tree: Tree) =
+ if (!emptyTree(tree)) super.printOpt(prefix, tree)
+
+ override def printColumn(ts: List[Tree], start: String, sep: String, end: String) = {
+ super.printColumn(ts.filter(!syntheticToRemove(_)), start, sep, end)
+ }
+
+ def printFlags(mods: Modifiers, primaryCtorParam: Boolean = false): Unit = {
+ val base = AccessFlags | OVERRIDE | ABSTRACT | FINAL | SEALED | LAZY
+ val mask = if (primaryCtorParam) base else base | IMPLICIT
+
+ val s = mods.flagString(mask)
+ if (s != "") print(s"$s ")
+ // case flag should be the last
+ if (mods.isCase) print(mods.flagBitsToString(CASE) + " ")
+ if (mods.isAbstractOverride) print("abstract override ")
+ }
+
+ override def printModifiers(tree: Tree, mods: Modifiers): Unit = printModifiers(mods, primaryCtorParam = false)
+
+ def printModifiers(mods: Modifiers, primaryCtorParam: Boolean): Unit = {
+ def modsAccepted = List(currentTree, currentParent) exists (_ map {
+ case _: ClassDef | _: ModuleDef | _: Template | _: PackageDef => true
+ case _ => false
+ } getOrElse false)
+
+ if (currentParent.isEmpty || modsAccepted)
+ printFlags(mods, primaryCtorParam)
+ else
+ List(IMPLICIT, CASE, LAZY, SEALED).foreach{flag => if (mods.hasFlag(flag)) print(s"${mods.flagBitsToString(flag)} ")}
+ }
+
+ def printParam(tree: Tree, primaryCtorParam: Boolean): Unit =
+ tree match {
+ case vd @ ValDef(mods, name, tp, rhs) =>
+ printPosition(tree)
+ printAnnotations(vd)
+ val mutableOrOverride = mods.isOverride || mods.isMutable
+ val hideCtorMods = mods.isParamAccessor && mods.isPrivateLocal && !mutableOrOverride
+ val hideCaseCtorMods = mods.isCaseAccessor && mods.isPublic && !mutableOrOverride
+
+ if (primaryCtorParam && !(hideCtorMods || hideCaseCtorMods)) {
+ printModifiers(mods, primaryCtorParam)
+ print(if (mods.isMutable) "var " else "val ");
+ }
+ print(printedName(name), blankForName(name));
+ printOpt(": ", tp);
+ printOpt(" = ", rhs)
+ case TypeDef(_, name, tparams, rhs) =>
+ printPosition(tree)
+ print(printedName(name))
+ printTypeParams(tparams);
+ print(rhs)
+ case _ =>
+ super.printParam(tree)
+ }
+
+ override def printParam(tree: Tree): Unit = {
+ printParam(tree, primaryCtorParam = false)
+ }
+
+ protected def printArgss(argss: List[List[Tree]]) =
+ argss foreach {x: List[Tree] => if (!(x.isEmpty && argss.size == 1)) printRow(x, "(", ", ", ")")}
+
+ override def printAnnotations(tree: MemberDef) = {
+ val annots = tree.mods.annotations
+ annots foreach {annot => printAnnot(annot); print(" ")}
+ }
+
+ protected def printAnnot(tree: Tree) = {
+ tree match {
+ case treeInfo.Applied(core, _, argss) =>
+ print("@")
+ core match {
+ case Select(New(tree), _) => print(tree)
+ case _ =>
+ }
+ printArgss(argss)
+ case _ => super.printTree(tree)
+ }
+ }
+
+ override def printTree(tree: Tree): Unit = {
+ parentsStack.push(tree)
+ try {
+ processTreePrinting(tree);
+ printTypesInfo(tree)
+ } finally parentsStack.pop()
+ }
+
+ def processTreePrinting(tree: Tree): Unit = {
+ tree match {
+ // don't remove synthetic ValDef/TypeDef
+ case _ if syntheticToRemove(tree) =>
+
+ case cl @ ClassDef(mods, name, tparams, impl) =>
+ if (mods.isJavaDefined) super.printTree(cl)
+ printAnnotations(cl)
+ // traits
+ val clParents: List[Tree] = if (mods.isTrait) {
+ // avoid abstract modifier for traits
+ printModifiers(tree, mods &~ ABSTRACT)
+ print("trait ", printedName(name))
+ printTypeParams(tparams)
+
+ val build.SyntacticTraitDef(_, _, _, _, parents, _, _) = tree
+ parents
+ // classes
+ } else {
+ printModifiers(tree, mods)
+ print("class ", printedName(name))
+ printTypeParams(tparams)
+
+ val build.SyntacticClassDef(_, _, _, ctorMods, vparamss, earlyDefs, parents, selfType, body) = cl
+
+ // constructor's modifier
+ if (ctorMods.hasFlag(AccessFlags)) {
+ print(" ")
+ printModifiers(ctorMods, primaryCtorParam = false)
+ }
+
+ def printConstrParams(ts: List[ValDef]): Unit = {
+ parenthesize() {
+ printImplicitInParamsList(ts)
+ printSeq(ts)(printParam(_, primaryCtorParam = true))(print(", "))
+ }
+ }
+ // constructor's params processing (don't print single empty constructor param list)
+ vparamss match {
+ case Nil | List(Nil) if (!mods.isCase && !ctorMods.hasFlag(AccessFlags)) =>
+ case _ => vparamss foreach printConstrParams
+ }
+ parents
+ }
+
+ // get trees without default classes and traits (when they are last)
+ val printedParents = removeDefaultTypesFromList(clParents)()(if (mods.hasFlag(CASE)) defaultTraitsForCase else Nil)
+ print(if (mods.isDeferred) "<: " else if (printedParents.nonEmpty) " extends " else "", impl)
+
+ case pd @ PackageDef(packaged, stats) =>
+ packaged match {
+ case Ident(name) if name == nme.EMPTY_PACKAGE_NAME =>
+ printSeq(stats) {
+ print(_)
+ } {
+ println()
+ println()
+ };
+ case _ =>
+ printPackageDef(pd, scala.util.Properties.lineSeparator)
+ }
+
+ case md @ ModuleDef(mods, name, impl) =>
+ printAnnotations(md)
+ printModifiers(tree, mods)
+ val Template(parents, self, methods) = impl
+ val parWithoutAnyRef = removeDefaultClassesFromList(parents)
+ print("object " + printedName(name), if (parWithoutAnyRef.nonEmpty) " extends " else "", impl)
+
+ case vd @ ValDef(mods, name, tp, rhs) =>
+ printValDef(vd, printedName(name)) {
+ // place space after symbolic def name (val *: Unit does not compile)
+ printOpt(s"${blankForName(name)}: ", tp)
+ } {
+ if (!mods.isDeferred) print(" = ", if (rhs.isEmpty) "_" else rhs)
+ }
+
+ case dd @ DefDef(mods, name, tparams, vparamss, tp, rhs) =>
+ printDefDef(dd, printedName(name)) {
+ if (tparams.isEmpty && (vparamss.isEmpty || vparamss(0).isEmpty)) print(blankForName(name))
+ printOpt(": ", tp)
+ } {
+ printOpt(" = " + (if (mods.isMacro) "macro " else ""), rhs)
+ }
+
+ case td @ TypeDef(mods, name, tparams, rhs) =>
+ printTypeDef(td, printedName(name))
+
+ case LabelDef(name, params, rhs) =>
+ if (name.startsWith(nme.WHILE_PREFIX)) {
+ val If(cond, thenp, elsep) = rhs
+ print("while (", cond, ") ")
+ val Block(list, wh) = thenp
+ printColumn(list, "", ";", "")
+ } else if (name.startsWith(nme.DO_WHILE_PREFIX)) {
+ val Block(bodyList, ifCond @ If(cond, thenp, elsep)) = rhs
+ print("do ")
+ printColumn(bodyList, "", ";", "")
+ print(" while (", cond, ") ")
+ } else {
+ print(printedName(name)); printLabelParams(params);
+ printBlock(rhs)
+ }
+
+ case imp @ Import(expr, _) =>
+ printImport(imp, resolveSelect(expr))
+
+ case t @ Template(parents, self, tbody) =>
+ val body = treeInfo.untypecheckedTemplBody(t)
+ val printedParents =
+ currentParent map {
+ case _: CompoundTypeTree => parents
+ case ClassDef(mods, name, _, _) if mods.isCase => removeDefaultTypesFromList(parents)()(List(tpnme.Product, tpnme.Serializable))
+ case _ => removeDefaultClassesFromList(parents)
+ } getOrElse (parents)
+
+ val primaryCtr = treeInfo.firstConstructor(body)
+ val ap: Option[Apply] = primaryCtr match {
+ case DefDef(_, _, _, _, _, Block(ctBody, _)) =>
+ val earlyDefs = treeInfo.preSuperFields(ctBody) ::: body.filter {
+ case td: TypeDef => treeInfo.isEarlyDef(td)
+ case _ => false
+ }
+ if (earlyDefs.nonEmpty) {
+ print("{")
+ printColumn(earlyDefs, "", ";", "")
+ print("} " + (if (printedParents.nonEmpty) "with " else ""))
+ }
+ ctBody collectFirst {
+ case apply: Apply => apply
+ }
+ case _ => None
+ }
+
+ if (printedParents.nonEmpty) {
+ val (clParent :: traits) = printedParents
+ print(clParent)
+
+ val constrArgss = ap match {
+ case Some(treeInfo.Applied(_, _, argss)) => argss
+ case _ => Nil
+ }
+ printArgss(constrArgss)
+ if (traits.nonEmpty) {
+ printRow(traits, " with ", " with ", "")
+ }
+ }
+ /* Remove primary constr def and constr val and var defs
+ * right contains all constructors
+ */
+ val (left, right) = body.filter {
+ // remove valdefs defined in constructor and presuper vals
+ case vd: ValDef => !vd.mods.isParamAccessor && !treeInfo.isEarlyValDef(vd)
+ // remove $this$ from traits
+ case dd: DefDef => dd.name != nme.MIXIN_CONSTRUCTOR
+ case td: TypeDef => !treeInfo.isEarlyDef(td)
+ case EmptyTree => false
+ case _ => true
+ } span {
+ case dd: DefDef => dd.name != nme.CONSTRUCTOR
+ case _ => true
+ }
+ val modBody = (left ::: right.drop(1))
+ val showBody = !(modBody.isEmpty && (self == noSelfType || self.isEmpty))
+ if (showBody) {
+ if (self.name != nme.WILDCARD) {
+ print(" { ", self.name);
+ printOpt(": ", self.tpt);
+ print(" =>")
+ } else if (self.tpt.nonEmpty) {
+ print(" { _ : ", self.tpt, " =>")
+ } else {
+ print(" {")
+ }
+ printColumn(modBody, "", ";", "}")
+ }
+
+ case bl @ Block(stats, expr) =>
+ printBlock(treeInfo.untypecheckedBlockBody(bl), expr)
+
+ case Match(selector, cases) =>
+ /* Insert braces if match is inner
+ * make this function available for other cases
+ * passing required type for checking
+ */
+ def insertBraces(body: => Unit): Unit =
+ if (parentsStack.nonEmpty && parentsStack.tail.exists(_.isInstanceOf[Match])) {
+ print("(")
+ body
+ print(")")
+ } else body
+
+ val printParentheses = needsParentheses(selector)(insideLabelDef = false)
+ tree match {
+ case Match(EmptyTree, cs) =>
+ printColumn(cases, "{", "", "}")
+ case _ =>
+ insertBraces {
+ parenthesize(printParentheses)(print(selector))
+ printColumn(cases, " match {", "", "}")
+ }
+ }
+
+ case cd @ CaseDef(pat, guard, body) =>
+ printCaseDef(cd)
+
+ case Star(elem) =>
+ print(elem, "*")
+
+ case Bind(name, t) =>
+ if (t == EmptyTree) print("(", printedName(name), ")")
+ else if (t.exists(_.isInstanceOf[Star])) print(printedName(name), " @ ", t)
+ else print("(", printedName(name), " @ ", t, ")")
+
+ case f @ Function(vparams, body) =>
+ // parentheses are not allowed for val a: Int => Int = implicit x => x
+ val printParentheses = vparams match {
+ case head :: _ => !head.mods.isImplicit
+ case _ => true
+ }
+ printFunction(f)(printValueParams(vparams, inParentheses = printParentheses))
+
+ case Typed(expr, tp) =>
+ def printTp = print("(", tp, ")")
+
+ tp match {
+ case EmptyTree | build.SyntacticEmptyTypeTree() => printTp
+ // case for untypechecked trees
+ case Annotated(annot, arg) if (expr ne null) && (arg ne null) && expr.equalsStructure(arg) => printTp // remove double arg - 5: 5: @unchecked
+ case tt: TypeTree if tt.original.isInstanceOf[Annotated] => printTp
+ case Function(List(), EmptyTree) => print("(", expr, " _)") //func _
+ // parentheses required when (a match {}) : Type
+ case _ => print("((", expr, "): ", tp, ")")
+ }
+
+ // print only fun when targs are TypeTrees with empty original
+ case TypeApply(fun, targs) =>
+ if (targs.exists(emptyTree(_))) {
+ print(fun)
+ } else super.printTree(tree)
+
+ case Apply(fun, vargs) =>
+ tree match {
+ // processing methods ending on colons (x \: list)
+ case Apply(Block(l1 @ List(sVD: ValDef), a1 @ Apply(Select(_, methodName), l2 @ List(Ident(iVDName)))), l3)
+ if sVD.mods.isSynthetic && treeInfo.isLeftAssoc(methodName) && sVD.name == iVDName =>
+ val printBlock = Block(l1, Apply(a1, l3))
+ print(printBlock)
+ case Apply(tree1, _) if (needsParentheses(tree1)(insideAnnotated = false)) =>
+ parenthesize()(print(fun)); printRow(vargs, "(", ", ", ")")
+ case _ => super.printTree(tree)
+ }
+
+ case UnApply(fun, args) =>
+ fun match {
+ case treeInfo.Unapplied(body) =>
+ body match {
+ case Select(qual, name) if name == nme.unapply => print(qual)
+ case TypeApply(Select(qual, name), args) if name == nme.unapply || name == nme.unapplySeq =>
+ print(TypeApply(qual, args))
+ case _ => print(body)
+ }
+ case _ => print(fun)
+ }
+ printRow(args, "(", ", ", ")")
+
+ case st @ Super(This(qual), mix) =>
+ printSuper(st, printedName(qual), checkSymbol = false)
+
+ case th @ This(qual) =>
+ if (tree.hasExistingSymbol && tree.symbol.isPackage) print(tree.symbol.fullName)
+ else printThis(th, printedName(qual))
+
+ // remove this prefix from constructor invocation in typechecked trees: this.this -> this
+ case Select(This(_), name @ nme.CONSTRUCTOR) => print(printedName(name))
+
+ case Select(qual: New, name) =>
+ print(qual)
+
+ case Select(qual, name) =>
+ def checkRootPackage(tr: Tree): Boolean =
+ (currentParent match { //check that Select is not for package def name
+ case Some(_: PackageDef) => false
+ case _ => true
+ }) && (tr match { // check that Select contains package
+ case Select(q, _) => checkRootPackage(q)
+ case _: Ident | _: This => val sym = tr.symbol
+ tr.hasExistingSymbol && sym.isPackage && sym.name != nme.ROOTPKG
+ case _ => false
+ })
+
+ if (printRootPkg && checkRootPackage(tree)) print(s"${printedName(nme.ROOTPKG)}.")
+ val printParentheses = needsParentheses(qual)(insideAnnotated = false) || isIntLitWithDecodedOp(qual, name)
+ if (printParentheses) print("(", resolveSelect(qual), ").", printedName(name))
+ else print(resolveSelect(qual), ".", printedName(name))
+
+ case id @ Ident(name) =>
+ if (name.nonEmpty) {
+ if (name == nme.dollarScope) {
+ print(s"scala.xml.${nme.TopScope}")
+ } else {
+ val str = printedName(name)
+ val strIsBackquoted = str.startsWith("`") && str.endsWith("`")
+ print(if (id.isBackquoted && !strIsBackquoted) "`" + str + "`" else str)
+ }
+ } else {
+ print("")
+ }
+
+ case l @ Literal(x) =>
+ import Chars.LF
+ x match {
+ case Constant(v: String) if {
+ val strValue = x.stringValue
+ strValue.contains(LF) && strValue.contains("\"\"\"") && strValue.size > 1
+ } =>
+ val splitValue = x.stringValue.split(s"$LF").toList
+ val multilineStringValue = if (x.stringValue.endsWith(s"$LF")) splitValue :+ "" else splitValue
+ val trQuotes = "\"\"\""
+ print(trQuotes); printSeq(multilineStringValue) { print(_) } { print(LF) }; print(trQuotes)
+ case _ =>
+ // processing Float constants
+ val printValue = x.escapedStringValue + (if (x.value.isInstanceOf[Float]) "F" else "")
+ print(printValue)
+ }
+
+ case an @ Annotated(ap, tree) =>
+ val printParentheses = needsParentheses(tree)()
+ parenthesize(printParentheses) { print(tree) }; print(if (tree.isType) " " else ": ")
+ printAnnot(ap)
+
+ case SelectFromTypeTree(qualifier, selector) =>
+ print("(", qualifier, ")#", blankForOperatorName(selector), printedName(selector))
+
+ case tt: TypeTree =>
+ if (!emptyTree(tt)) print(tt.original)
+
+ case AppliedTypeTree(tp, args) =>
+ // it's possible to have (=> String) => String type but Function1[=> String, String] is not correct
+ val containsByNameTypeParam = args exists treeInfo.isByNameParamType
+
+ if (containsByNameTypeParam) {
+ print("(")
+ printRow(args.init, "(", ", ", ")")
+ print(" => ", args.last, ")")
+ } else {
+ if (treeInfo.isRepeatedParamType(tree) && args.nonEmpty) {
+ print(args(0), "*")
+ } else if (treeInfo.isByNameParamType(tree)) {
+ print("=> ", if (args.isEmpty) "()" else args(0))
+ } else
+ super.printTree(tree)
+ }
+
+ case ExistentialTypeTree(tpt, whereClauses) =>
+ print("(", tpt);
+ printColumn(whereClauses, " forSome { ", ";", "})")
+
+ case EmptyTree =>
+
+ case tree => super.printTree(tree)
+ }
+ }
+ }
+
/** Hook for extensions */
def xprintTree(treePrinter: TreePrinter, tree: Tree) =
treePrinter.print(tree.productPrefix+tree.productIterator.mkString("(", ", ", ")"))
+ def newCodePrinter(writer: PrintWriter, tree: Tree, printRootPkg: Boolean): TreePrinter =
+ new CodePrinter(writer, printRootPkg)
+
def newTreePrinter(writer: PrintWriter): TreePrinter = new TreePrinter(writer)
def newTreePrinter(stream: OutputStream): TreePrinter = newTreePrinter(new PrintWriter(stream))
def newTreePrinter(): TreePrinter = newTreePrinter(new PrintWriter(ConsoleWriter))
@@ -475,8 +1118,6 @@ trait Printers extends api.Printers { self: SymbolTable =>
}
def newRawTreePrinter(writer: PrintWriter): RawTreePrinter = new RawTreePrinter(writer)
- def newRawTreePrinter(stream: OutputStream): RawTreePrinter = newRawTreePrinter(new PrintWriter(stream))
- def newRawTreePrinter(): RawTreePrinter = newRawTreePrinter(new PrintWriter(ConsoleWriter))
// provides footnotes for types and mirrors
import scala.collection.mutable.{Map, WeakHashMap, SortedSet}
@@ -525,7 +1166,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
private var depth = 0
private var printTypesInFootnotes = true
private var printingFootnotes = false
- private var footnotes = footnoteIndex.mkFootnotes()
+ private val footnotes = footnoteIndex.mkFootnotes()
def print(args: Any*): Unit = {
// don't print type footnotes if the argument is a mere type
@@ -542,14 +1183,17 @@ trait Printers extends api.Printers { self: SymbolTable =>
print(")")
case EmptyTree =>
print("EmptyTree")
- case emptyValDef: AnyRef if emptyValDef eq self.emptyValDef =>
- print("emptyValDef")
+ case self.noSelfType =>
+ print("noSelfType")
+ case self.pendingSuperCall =>
+ print("pendingSuperCall")
case tree: Tree =>
- val hasSymbol = tree.hasSymbol && tree.symbol != NoSymbol
- val isError = hasSymbol && tree.symbol.name.toString == nme.ERROR.toString
+ def hasSymbolField = tree.hasSymbolField && tree.symbol != NoSymbol
+ val isError = hasSymbolField && (tree.symbol.name string_== nme.ERROR)
printProduct(
tree,
preamble = _ => {
+ if (printPositions) print(tree.pos.show)
print(tree.productPrefix)
if (printTypes && tree.tpe != null) print(tree.tpe)
},
@@ -559,7 +1203,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
if (isError) print("<")
print(name)
if (isError) print(": error>")
- } else if (hasSymbol) {
+ } else if (hasSymbolField) {
tree match {
case refTree: RefTree =>
if (tree.symbol.name != refTree.name) print("[", tree.symbol, " aka ", refTree.name, "]")
@@ -590,6 +1234,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
else if (sym.isStatic && (sym.isClass || sym.isModule)) print(sym.fullName)
else print(sym.name)
if (printIds) print("#", sym.id)
+ if (printOwners) print("@", sym.owner.id)
if (printKinds) print("#", sym.abbreviatedKindString)
if (printMirrors) print("%M", footnotes.put[scala.reflect.api.Mirror[_]](mirrorThatLoaded(sym)))
case tag: TypeTag[_] =>
@@ -653,7 +1298,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
print("(")
val it = iterable.iterator
while (it.hasNext) {
- body(it.next)
+ body(it.next())
print(if (it.hasNext) ", " else "")
}
print(")")
@@ -662,19 +1307,19 @@ trait Printers extends api.Printers { self: SymbolTable =>
}
def show(name: Name): String = name match {
- case tpnme.WILDCARD => "tpnme.WILDCARD"
- case tpnme.EMPTY => "tpnme.EMPTY"
- case tpnme.ERROR => "tpnme.ERROR"
- case tpnme.PACKAGE => "tpnme.PACKAGE"
- case tpnme.WILDCARD_STAR => "tpnme.WILDCARD_STAR"
- case nme.WILDCARD => "nme.WILDCARD"
- case nme.EMPTY => "nme.EMPTY"
- case nme.ERROR => "tpnme.ERROR"
- case nme.PACKAGE => "nme.PACKAGE"
- case nme.CONSTRUCTOR => "nme.CONSTRUCTOR"
- case nme.ROOTPKG => "nme.ROOTPKG"
+ case tpnme.WILDCARD => "typeNames.WILDCARD"
+ case tpnme.EMPTY => "typeNames.EMPTY"
+ case tpnme.ERROR => "typeNames.ERROR"
+ case tpnme.PACKAGE => "typeNames.PACKAGE"
+ case tpnme.WILDCARD_STAR => "typeNames.WILDCARD_STAR"
+ case nme.WILDCARD => "termNames.WILDCARD"
+ case nme.EMPTY => "termNames.EMPTY"
+ case nme.ERROR => "termNames.ERROR"
+ case nme.PACKAGE => "termNames.PACKAGE"
+ case nme.CONSTRUCTOR => "termNames.CONSTRUCTOR"
+ case nme.ROOTPKG => "termNames.ROOTPKG"
case _ =>
- val prefix = if (name.isTermName) "newTermName(\"" else "newTypeName(\""
+ val prefix = if (name.isTermName) "TermName(\"" else "TypeName(\""
prefix + name.toString + "\")"
}
@@ -688,4 +1333,13 @@ trait Printers extends api.Printers { self: SymbolTable =>
s_flags mkString " | "
}
}
+
+ def show(position: Position): String = {
+ position.show
+ }
+
+ def showDecl(sym: Symbol): String = {
+ if (!isCompilerUniverse) definitions.fullyInitializeSymbol(sym)
+ sym.defString
+ }
}
diff --git a/src/reflect/scala/reflect/internal/PrivateWithin.scala b/src/reflect/scala/reflect/internal/PrivateWithin.scala
new file mode 100644
index 0000000000..996f9c13bb
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/PrivateWithin.scala
@@ -0,0 +1,27 @@
+package scala
+package reflect
+package internal
+
+import java.lang.{ Class => jClass }
+import java.lang.reflect.{ Member => jMember }
+
+trait PrivateWithin {
+ self: SymbolTable =>
+
+ def propagatePackageBoundary(c: jClass[_], syms: Symbol*): Unit =
+ propagatePackageBoundary(JavaAccFlags(c), syms: _*)
+ def propagatePackageBoundary(m: jMember, syms: Symbol*): Unit =
+ propagatePackageBoundary(JavaAccFlags(m), syms: _*)
+ def propagatePackageBoundary(jflags: JavaAccFlags, syms: Symbol*) {
+ if (jflags.hasPackageAccessBoundary)
+ syms foreach setPackageAccessBoundary
+ }
+
+ // protected in java means package protected. #3946
+ // See ticket #1687 for an example of when the enclosing top level class is NoSymbol;
+ // it apparently occurs when processing v45.3 bytecode.
+ def setPackageAccessBoundary(sym: Symbol): Symbol = (
+ if (sym.enclosingTopLevelClass eq NoSymbol) sym
+ else sym setPrivateWithin sym.enclosingTopLevelClass.owner
+ )
+}
diff --git a/src/reflect/scala/reflect/internal/ReificationSupport.scala b/src/reflect/scala/reflect/internal/ReificationSupport.scala
new file mode 100644
index 0000000000..ad8a2594dd
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/ReificationSupport.scala
@@ -0,0 +1,1146 @@
+package scala
+package reflect
+package internal
+
+import Flags._
+import util._
+
+trait ReificationSupport { self: SymbolTable =>
+ import definitions._
+ import internal._
+
+ class ReificationSupportImpl extends ReificationSupportApi {
+ def selectType(owner: Symbol, name: String): TypeSymbol =
+ select(owner, newTypeName(name)).asType
+
+ def selectTerm(owner: Symbol, name: String): TermSymbol = {
+ val result = select(owner, newTermName(name)).asTerm
+ if (result.isOverloaded) result.suchThat(!_.isMethod).asTerm
+ else result
+ }
+
+ protected def select(owner: Symbol, name: Name): Symbol = {
+ val result = owner.info decl name
+ if (result ne NoSymbol) result
+ else
+ mirrorThatLoaded(owner).missingHook(owner, name) orElse {
+ throw new ScalaReflectionException("%s %s in %s not found".format(if (name.isTermName) "term" else "type", 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.asMethod
+ else throw new ScalaReflectionException("overloaded method %s #%d in %s not found".format(name, index, owner.fullName))
+ }
+
+ def newFreeTerm(name: String, value: => Any, flags: Long = 0L, origin: String = null): FreeTermSymbol =
+ newFreeTermSymbol(newTermName(name), value, flags, origin).markFlagsCompleted(mask = AllFlags)
+
+ def newFreeType(name: String, flags: Long = 0L, origin: String = null): FreeTypeSymbol =
+ newFreeTypeSymbol(newTypeName(name), flags, origin).markFlagsCompleted(mask = AllFlags)
+
+ def newNestedSymbol(owner: Symbol, name: Name, pos: Position, flags: Long, isClass: Boolean): Symbol =
+ owner.newNestedSymbol(name, pos, flags, isClass).markFlagsCompleted(mask = AllFlags)
+
+ def newScopeWith(elems: Symbol*): Scope =
+ self.newScopeWith(elems: _*)
+
+ def setAnnotations[S <: Symbol](sym: S, annots: List[AnnotationInfo]): S =
+ sym.setAnnotations(annots)
+
+ def setInfo[S <: Symbol](sym: S, tpe: Type): S =
+ sym.setInfo(tpe).markAllCompleted()
+
+ def mkThis(sym: Symbol): Tree = self.This(sym)
+
+ def mkSelect(qualifier: Tree, sym: Symbol): Select = self.Select(qualifier, sym)
+
+ def mkIdent(sym: Symbol): Ident = self.Ident(sym)
+
+ def mkTypeTree(tp: Type): TypeTree = self.TypeTree(tp)
+
+ def ThisType(sym: Symbol): Type = self.ThisType(sym)
+
+ def SingleType(pre: Type, sym: Symbol): Type = self.SingleType(pre, sym)
+
+ def SuperType(thistpe: Type, supertpe: Type): Type = self.SuperType(thistpe, supertpe)
+
+ def ConstantType(value: Constant): ConstantType = self.ConstantType(value)
+
+ def TypeRef(pre: Type, sym: Symbol, args: List[Type]): Type = self.TypeRef(pre, sym, args)
+
+ def RefinedType(parents: List[Type], decls: Scope, typeSymbol: Symbol): RefinedType = self.RefinedType(parents, decls, typeSymbol)
+
+ def ClassInfoType(parents: List[Type], decls: Scope, typeSymbol: Symbol): ClassInfoType = self.ClassInfoType(parents, decls, typeSymbol)
+
+ def MethodType(params: List[Symbol], resultType: Type): MethodType = self.MethodType(params, resultType)
+
+ def NullaryMethodType(resultType: Type): NullaryMethodType = self.NullaryMethodType(resultType)
+
+ def PolyType(typeParams: List[Symbol], resultType: Type): PolyType = self.PolyType(typeParams, resultType)
+
+ def ExistentialType(quantified: List[Symbol], underlying: Type): ExistentialType = self.ExistentialType(quantified, underlying)
+
+ def AnnotatedType(annotations: List[Annotation], underlying: Type): AnnotatedType = self.AnnotatedType(annotations, underlying)
+
+ def TypeBounds(lo: Type, hi: Type): TypeBounds = self.TypeBounds(lo, hi)
+
+ def BoundedWildcardType(bounds: TypeBounds): BoundedWildcardType = self.BoundedWildcardType(bounds)
+
+ 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 }
+
+ def toStats(tree: Tree): List[Tree] = tree match {
+ case EmptyTree => Nil
+ case SyntacticBlock(stats) => stats
+ case _ => throw new IllegalArgumentException(s"can't flatten $tree")
+ }
+
+ def mkAnnotation(tree: Tree): Tree = tree match {
+ case SyntacticNew(Nil, SyntacticApplied(SyntacticAppliedType(_, _), _) :: Nil, noSelfType, Nil) =>
+ tree
+ case _ =>
+ throw new IllegalArgumentException(s"Tree ${showRaw(tree)} isn't a correct representation of annotation." +
+ """Consider reformatting it into a q"new $name[..$targs](...$argss)" shape""")
+ }
+
+ def mkAnnotation(trees: List[Tree]): List[Tree] = trees.map(mkAnnotation)
+
+ def mkParam(argss: List[List[Tree]], extraFlags: FlagSet = NoFlags, excludeFlags: FlagSet = DEFERRED): List[List[ValDef]] =
+ argss.map { args => args.map { mkParam(_, extraFlags, excludeFlags) } }
+
+ def mkParam(tree: Tree, extraFlags: FlagSet, excludeFlags: FlagSet): ValDef = tree match {
+ case Typed(Ident(name: TermName), tpt) =>
+ mkParam(ValDef(NoMods, name, tpt, EmptyTree), extraFlags, excludeFlags)
+ case vd: ValDef =>
+ var newmods = vd.mods & (~excludeFlags)
+ if (vd.rhs.nonEmpty) newmods |= DEFAULTPARAM
+ copyValDef(vd)(mods = newmods | extraFlags)
+ case _ =>
+ throw new IllegalArgumentException(s"$tree is not valid represenation of a parameter, " +
+ """consider reformatting it into q"val $name: $T = $default" shape""")
+ }
+
+ def mkImplicitParam(args: List[Tree]): List[ValDef] = args.map(mkImplicitParam)
+
+ def mkImplicitParam(tree: Tree): ValDef = mkParam(tree, IMPLICIT | PARAM, NoFlags)
+
+ def mkTparams(tparams: List[Tree]): List[TypeDef] =
+ tparams.map {
+ case td: TypeDef => copyTypeDef(td)(mods = (td.mods | PARAM) & (~DEFERRED))
+ case other => throw new IllegalArgumentException(s"can't splice $other as type parameter")
+ }
+
+ def mkRefineStat(stat: Tree): Tree = {
+ stat match {
+ case dd: DefDef => require(dd.rhs.isEmpty, "can't use DefDef with non-empty body as refine stat")
+ case vd: ValDef => require(vd.rhs.isEmpty, "can't use ValDef with non-empty rhs as refine stat")
+ case td: TypeDef =>
+ case _ => throw new IllegalArgumentException(s"not legal refine stat: $stat")
+ }
+ stat
+ }
+
+ def mkRefineStat(stats: List[Tree]): List[Tree] = stats.map(mkRefineStat)
+
+ def mkPackageStat(stat: Tree): Tree = {
+ stat match {
+ case cd: ClassDef =>
+ case md: ModuleDef =>
+ case pd: PackageDef =>
+ case _ => throw new IllegalArgumentException(s"not legal package stat: $stat")
+ }
+ stat
+ }
+
+ def mkPackageStat(stats: List[Tree]): List[Tree] = stats.map(mkPackageStat)
+
+ object ScalaDot extends ScalaDotExtractor {
+ def apply(name: Name): Tree = gen.scalaDot(name)
+ def unapply(tree: Tree): Option[Name] = tree match {
+ case Select(id @ Ident(nme.scala_), name) if id.symbol == ScalaPackage => Some(name)
+ case _ => None
+ }
+ }
+
+ def mkEarlyDef(defn: Tree): Tree = defn match {
+ case vdef @ ValDef(mods, _, _, _) if !mods.isDeferred =>
+ copyValDef(vdef)(mods = mods | PRESUPER)
+ case tdef @ TypeDef(mods, _, _, _) =>
+ copyTypeDef(tdef)(mods = mods | PRESUPER)
+ case _ =>
+ throw new IllegalArgumentException(s"not legal early def: $defn")
+ }
+
+ def mkEarlyDef(defns: List[Tree]): List[Tree] = defns.map(mkEarlyDef)
+
+ def mkRefTree(qual: Tree, sym: Symbol) = self.RefTree(qual, sym.name) setSymbol sym
+
+ def freshTermName(prefix: String = nme.FRESH_TERM_NAME_PREFIX): TermName = self.freshTermName(prefix)
+
+ def freshTypeName(prefix: String): TypeName = self.freshTypeName(prefix)
+
+ protected implicit def fresh: FreshNameCreator = self.currentFreshNameCreator
+
+ object ImplicitParams extends ImplicitParamsExtractor {
+ def apply(paramss: List[List[Tree]], implparams: List[Tree]): List[List[Tree]] =
+ if (implparams.nonEmpty) paramss :+ mkImplicitParam(implparams) else paramss
+
+ def unapply(vparamss: List[List[ValDef]]): Some[(List[List[ValDef]], List[ValDef])] = vparamss match {
+ case init :+ (last @ (initlast :: _)) if initlast.mods.isImplicit => Some((init, last))
+ case _ => Some((vparamss, Nil))
+ }
+ }
+
+ object FlagsRepr extends FlagsReprExtractor {
+ def apply(bits: Long): FlagSet = bits
+ def unapply(flags: Long): Some[Long] = Some(flags)
+ }
+
+ /** Construct/deconstruct type application term trees.
+ * Treats other term trees as zero-argument type applications.
+ */
+ object SyntacticTypeApplied extends SyntacticTypeAppliedExtractor {
+ def apply(tree: Tree, targs: List[Tree]): Tree =
+ if (targs.isEmpty) tree
+ else if (tree.isTerm) TypeApply(tree, targs)
+ else throw new IllegalArgumentException(s"can't apply type arguments to $tree")
+
+ def unapply(tree: Tree): Option[(Tree, List[Tree])] = tree match {
+ case TypeApply(fun, targs) => Some((fun, targs))
+ case _ if tree.isTerm => Some((tree, Nil))
+ case _ => None
+ }
+ }
+
+ /** Construct/deconstruct applied type trees.
+ * Treats other types as zero-arity applied types.
+ */
+ object SyntacticAppliedType extends SyntacticTypeAppliedExtractor {
+ def apply(tree: Tree, targs: List[Tree]): Tree =
+ if (targs.isEmpty) tree
+ else if (tree.isType) AppliedTypeTree(tree, targs)
+ else throw new IllegalArgumentException(s"can't create applied type from non-type $tree")
+
+ def unapply(tree: Tree): Option[(Tree, List[Tree])] = tree match {
+ case MaybeTypeTreeOriginal(AppliedTypeTree(tpe, targs)) => Some((tpe, targs))
+ case _ if tree.isType => Some((tree, Nil))
+ case _ => None
+ }
+ }
+
+ object SyntacticApplied extends SyntacticAppliedExtractor {
+ def apply(tree: Tree, argss: List[List[Tree]]): Tree =
+ argss.foldLeft(tree) { (f, args) => Apply(f, args.map(treeInfo.assignmentToMaybeNamedArg)) }
+
+ def unapply(tree: Tree): Some[(Tree, List[List[Tree]])] = tree match {
+ case UnApply(treeInfo.Unapplied(Select(fun, nme.unapply)), pats) =>
+ Some((fun, pats :: Nil))
+ case treeInfo.Applied(fun, targs, argss) =>
+ fun match {
+ case Select(_: New, nme.CONSTRUCTOR) =>
+ Some((tree, Nil))
+ case _ =>
+ val callee =
+ if (fun.isTerm) SyntacticTypeApplied(fun, targs)
+ else SyntacticAppliedType(fun, targs)
+ Some((callee, argss))
+ }
+ }
+ }
+
+ // recover constructor contents generated by gen.mkTemplate
+ protected object UnCtor {
+ def unapply(tree: Tree): Option[(Modifiers, List[List[ValDef]], List[Tree])] = tree match {
+ case DefDef(mods, nme.MIXIN_CONSTRUCTOR, _, _, _, SyntacticBlock(lvdefs :+ _)) =>
+ Some((mods | Flag.TRAIT, Nil, lvdefs))
+ case DefDef(mods, nme.CONSTRUCTOR, Nil, vparamss, _, SyntacticBlock(lvdefs :+ _ :+ _)) =>
+ Some((mods, vparamss, lvdefs))
+ case _ => None
+ }
+ }
+
+ // undo gen.mkTemplate
+ protected object UnMkTemplate {
+ def unapply(templ: Template): Option[(List[Tree], ValDef, Modifiers, List[List[ValDef]], List[Tree], List[Tree])] = {
+ val Template(parents, selfType, _) = templ
+ val tbody = treeInfo.untypecheckedTemplBody(templ)
+
+ def result(ctorMods: Modifiers, vparamss: List[List[ValDef]], edefs: List[Tree], body: List[Tree]) =
+ Some((parents, selfType, ctorMods, vparamss, edefs, body))
+ def indexOfCtor(trees: List[Tree]) =
+ trees.indexWhere { case UnCtor(_, _, _) => true ; case _ => false }
+
+ if (tbody forall treeInfo.isInterfaceMember)
+ result(NoMods | Flag.TRAIT, Nil, Nil, tbody)
+ else if (indexOfCtor(tbody) == -1)
+ None
+ else {
+ val (rawEdefs, rest) = tbody.span(treeInfo.isEarlyDef)
+ val (gvdefs, etdefs) = rawEdefs.partition(treeInfo.isEarlyValDef)
+ val (fieldDefs, UnCtor(ctorMods, ctorVparamss, lvdefs) :: body) = rest.splitAt(indexOfCtor(rest))
+ val evdefs = gvdefs.zip(lvdefs).map {
+ case (gvdef @ ValDef(_, _, tpt: TypeTree, _), ValDef(_, _, _, rhs)) =>
+ copyValDef(gvdef)(tpt = tpt.original, rhs = rhs)
+ }
+ val edefs = evdefs ::: etdefs
+ if (ctorMods.isTrait)
+ result(ctorMods, Nil, edefs, body)
+ else {
+ // undo conversion from (implicit ... ) to ()(implicit ... ) when its the only parameter section
+ val vparamssRestoredImplicits = ctorVparamss match {
+ case Nil :: (tail @ ((head :: _) :: _)) if head.mods.isImplicit => tail
+ case other => other
+ }
+ // undo flag modifications by merging flag info from constructor args and fieldDefs
+ val modsMap = fieldDefs.map { case ValDef(mods, name, _, _) => name -> mods }.toMap
+ def ctorArgsCorrespondToFields = vparamssRestoredImplicits.flatten.forall { vd => modsMap.contains(vd.name) }
+ if (!ctorArgsCorrespondToFields) None
+ else {
+ val vparamss = mmap(vparamssRestoredImplicits) { vd =>
+ val originalMods = modsMap(vd.name) | (vd.mods.flags & DEFAULTPARAM)
+ atPos(vd.pos)(ValDef(originalMods, vd.name, vd.tpt, vd.rhs))
+ }
+ result(ctorMods, vparamss, edefs, body)
+ }
+ }
+ }
+ }
+ }
+
+ protected def mkSelfType(tree: Tree) = tree match {
+ case vd: ValDef =>
+ require(vd.rhs.isEmpty, "self types must have empty right hand side")
+ copyValDef(vd)(mods = (vd.mods | PRIVATE) & (~DEFERRED))
+ case _ =>
+ throw new IllegalArgumentException(s"$tree is not a valid representation of self type, " +
+ """consider reformatting into q"val $self: $T" shape""")
+ }
+
+ object SyntacticClassDef extends SyntacticClassDefExtractor {
+ def apply(mods: Modifiers, name: TypeName, tparams: List[Tree],
+ constrMods: Modifiers, vparamss: List[List[Tree]],
+ earlyDefs: List[Tree], parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef = {
+ val extraFlags = PARAMACCESSOR | (if (mods.isCase) CASEACCESSOR else 0L)
+ val vparamss0 = mkParam(vparamss, extraFlags, excludeFlags = DEFERRED | PARAM)
+ val tparams0 = mkTparams(tparams)
+ val parents0 = gen.mkParents(mods,
+ if (mods.isCase) parents.filter {
+ case ScalaDot(tpnme.Product | tpnme.Serializable | tpnme.AnyRef) => false
+ case _ => true
+ } else parents
+ )
+ val body0 = earlyDefs ::: body
+ val selfType0 = mkSelfType(selfType)
+ val templ = gen.mkTemplate(parents0, selfType0, constrMods, vparamss0, body0)
+ gen.mkClassDef(mods, name, tparams0, templ)
+ }
+
+ def unapply(tree: Tree): Option[(Modifiers, TypeName, List[TypeDef], Modifiers, List[List[ValDef]],
+ List[Tree], List[Tree], ValDef, List[Tree])] = tree match {
+ case ClassDef(mods, name, tparams, UnMkTemplate(parents, selfType, ctorMods, vparamss, earlyDefs, body))
+ if !ctorMods.isTrait && !ctorMods.hasFlag(JAVA) =>
+ Some((mods, name, tparams, ctorMods, vparamss, earlyDefs, parents, selfType, body))
+ case _ =>
+ None
+ }
+ }
+
+ object SyntacticTraitDef extends SyntacticTraitDefExtractor {
+ def apply(mods: Modifiers, name: TypeName, tparams: List[Tree], earlyDefs: List[Tree],
+ parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef = {
+ val mods0 = mods | TRAIT | ABSTRACT
+ val templ = gen.mkTemplate(parents, mkSelfType(selfType), Modifiers(TRAIT), Nil, earlyDefs ::: body)
+ gen.mkClassDef(mods0, name, mkTparams(tparams), templ)
+ }
+
+ def unapply(tree: Tree): Option[(Modifiers, TypeName, List[TypeDef],
+ List[Tree], List[Tree], ValDef, List[Tree])] = tree match {
+ case ClassDef(mods, name, tparams, UnMkTemplate(parents, selfType, ctorMods, vparamss, earlyDefs, body))
+ if mods.isTrait =>
+ Some((mods, name, tparams, earlyDefs, parents, selfType, body))
+ case _ => None
+ }
+ }
+
+ object SyntacticObjectDef extends SyntacticObjectDefExtractor {
+ def apply(mods: Modifiers, name: TermName, earlyDefs: List[Tree],
+ parents: List[Tree], selfType: Tree, body: List[Tree]): ModuleDef =
+ ModuleDef(mods, name, gen.mkTemplate(parents, mkSelfType(selfType), NoMods, Nil, earlyDefs ::: body))
+
+ def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[Tree], ValDef, List[Tree])] = tree match {
+ case ModuleDef(mods, name, UnMkTemplate(parents, selfType, _, _, earlyDefs, body)) =>
+ Some((mods, name, earlyDefs, parents, selfType, body))
+ case _ =>
+ None
+ }
+ }
+
+ object SyntacticPackageObjectDef extends SyntacticPackageObjectDefExtractor {
+ def apply(name: TermName, earlyDefs: List[Tree],
+ parents: List[Tree], selfType: Tree, body: List[Tree]): PackageDef =
+ gen.mkPackageObject(SyntacticObjectDef(NoMods, name, earlyDefs, parents, selfType, body))
+
+ def unapply(tree: Tree): Option[(TermName, List[Tree], List[Tree], ValDef, List[Tree])] = tree match {
+ case PackageDef(Ident(name: TermName), List(SyntacticObjectDef(NoMods, nme.PACKAGEkw, earlyDefs, parents, selfType, body))) =>
+ Some((name, earlyDefs, parents, selfType, body))
+ case _ =>
+ None
+ }
+ }
+
+ // match references to `scala.$name`
+ protected class ScalaMemberRef(symbols: Seq[Symbol]) {
+ def result(name: Name): Option[Symbol] =
+ symbols.collect { case sym if sym.name == name => sym }.headOption
+ def unapply(tree: Tree): Option[Symbol] = tree match {
+ case id @ Ident(name) if symbols.contains(id.symbol) && name == id.symbol.name =>
+ Some(id.symbol)
+ case Select(scalapkg @ Ident(nme.scala_), name) if scalapkg.symbol == ScalaPackage =>
+ result(name)
+ case Select(Select(Ident(nme.ROOTPKG), nme.scala_), name) =>
+ result(name)
+ case _ => None
+ }
+ }
+ protected object TupleClassRef extends ScalaMemberRef(TupleClass.seq)
+ protected object TupleCompanionRef extends ScalaMemberRef(TupleClass.seq.map { _.companionModule })
+ protected object UnitClassRef extends ScalaMemberRef(Seq(UnitClass))
+ protected object FunctionClassRef extends ScalaMemberRef(FunctionClass.seq)
+
+ object SyntacticTuple extends SyntacticTupleExtractor {
+ def apply(args: List[Tree]): Tree = {
+ require(args.isEmpty || TupleClass(args.length).exists, s"Tuples with ${args.length} arity aren't supported")
+ gen.mkTuple(args)
+ }
+
+ def unapply(tree: Tree): Option[List[Tree]] = tree match {
+ case Literal(Constant(())) =>
+ Some(Nil)
+ case Apply(MaybeTypeTreeOriginal(SyntacticTypeApplied(MaybeSelectApply(TupleCompanionRef(sym)), targs)), args)
+ if sym == TupleClass(args.length).companionModule
+ && (targs.isEmpty || targs.length == args.length) =>
+ Some(args)
+ case _ if tree.isTerm =>
+ Some(tree :: Nil)
+ case _ =>
+ None
+ }
+ }
+
+ object SyntacticTupleType extends SyntacticTupleExtractor {
+ def apply(args: List[Tree]): Tree = {
+ require(args.isEmpty || TupleClass(args.length).exists, s"Tuples with ${args.length} arity aren't supported")
+ gen.mkTupleType(args)
+ }
+
+ def unapply(tree: Tree): Option[List[Tree]] = tree match {
+ case MaybeTypeTreeOriginal(UnitClassRef(_)) =>
+ Some(Nil)
+ case MaybeTypeTreeOriginal(AppliedTypeTree(TupleClassRef(sym), args))
+ if sym == TupleClass(args.length) =>
+ Some(args)
+ case _ if tree.isType =>
+ Some(tree :: Nil)
+ case _ =>
+ None
+ }
+ }
+
+ object SyntacticFunctionType extends SyntacticFunctionTypeExtractor {
+ def apply(argtpes: List[Tree], restpe: Tree): Tree = {
+ require(FunctionClass(argtpes.length).exists, s"Function types with ${argtpes.length} arity aren't supported")
+ gen.mkFunctionTypeTree(argtpes, restpe)
+ }
+
+ def unapply(tree: Tree): Option[(List[Tree], Tree)] = tree match {
+ case MaybeTypeTreeOriginal(AppliedTypeTree(FunctionClassRef(sym), args @ (argtpes :+ restpe)))
+ if sym == FunctionClass(args.length - 1) =>
+ Some((argtpes, restpe))
+ case _ => None
+ }
+ }
+
+ object SyntheticUnit {
+ def unapply(tree: Tree): Boolean = tree match {
+ case Literal(Constant(())) if tree.hasAttachment[SyntheticUnitAttachment.type] => true
+ case _ => false
+ }
+ }
+
+ /** Syntactic combinator that abstracts over Block tree.
+ *
+ * Apart from providing a more straightforward api that exposes
+ * block as a list of elements rather than (stats, expr) pair
+ * it also:
+ *
+ * 1. Strips trailing synthetic units which are inserted by the
+ * compiler if the block ends with a definition rather
+ * than an expression or is empty.
+ *
+ * 2. Matches non-block term trees and recognizes them as
+ * single-element blocks for sake of consistency with
+ * compiler's default to treat single-element blocks with
+ * expressions as just expressions. The only exception is q""
+ * which is not considered to be a block.
+ */
+ object SyntacticBlock extends SyntacticBlockExtractor {
+ def apply(stats: List[Tree]): Tree = gen.mkBlock(stats)
+
+ def unapply(tree: Tree): Option[List[Tree]] = tree match {
+ case bl @ self.Block(stats, SyntheticUnit()) => Some(treeInfo.untypecheckedBlockBody(bl))
+ case bl @ self.Block(stats, expr) => Some(treeInfo.untypecheckedBlockBody(bl) :+ expr)
+ case SyntheticUnit() => Some(Nil)
+ case _ if tree.isTerm && tree.nonEmpty => Some(tree :: Nil)
+ case _ => None
+ }
+ }
+
+ object SyntacticFunction extends SyntacticFunctionExtractor {
+ def apply(params: List[Tree], body: Tree): Function = {
+ val params0 :: Nil = mkParam(params :: Nil, PARAM)
+ require(params0.forall { _.rhs.isEmpty }, "anonymous functions don't support parameters with default values")
+ Function(params0, body)
+ }
+
+ def unapply(tree: Function): Option[(List[ValDef], Tree)] = Function.unapply(tree)
+ }
+
+ object SyntacticNew extends SyntacticNewExtractor {
+ def apply(earlyDefs: List[Tree], parents: List[Tree], selfType: Tree, body: List[Tree]): Tree =
+ gen.mkNew(parents, mkSelfType(selfType), earlyDefs ::: body, NoPosition, NoPosition)
+
+ def unapply(tree: Tree): Option[(List[Tree], List[Tree], ValDef, List[Tree])] = tree match {
+ case treeInfo.Applied(Select(New(SyntacticAppliedType(ident, targs)), nme.CONSTRUCTOR), Nil, List(Nil)) =>
+ Some((Nil, SyntacticAppliedType(ident, targs) :: Nil, noSelfType, Nil))
+ case treeInfo.Applied(Select(New(SyntacticAppliedType(ident, targs)), nme.CONSTRUCTOR), Nil, argss) =>
+ Some((Nil, SyntacticApplied(SyntacticAppliedType(ident, targs), argss) :: Nil, noSelfType, Nil))
+ case SyntacticBlock(SyntacticClassDef(_, tpnme.ANON_CLASS_NAME, Nil, _, ListOfNil, earlyDefs, parents, selfType, body) ::
+ Apply(Select(New(Ident(tpnme.ANON_CLASS_NAME)), nme.CONSTRUCTOR), Nil) :: Nil) =>
+ Some((earlyDefs, parents, selfType, body))
+ case _ =>
+ None
+ }
+ }
+
+ object SyntacticDefDef extends SyntacticDefDefExtractor {
+ def apply(mods: Modifiers, name: TermName, tparams: List[Tree],
+ vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef = {
+ val tparams0 = mkTparams(tparams)
+ val vparamss0 = mkParam(vparamss, PARAM)
+ val rhs0 = {
+ if (name != nme.CONSTRUCTOR) rhs
+ else rhs match {
+ case Block(_, _) => rhs
+ case _ => Block(List(rhs), gen.mkSyntheticUnit)
+ }
+ }
+ DefDef(mods, name, tparams0, vparamss0, tpt, rhs0)
+ }
+
+ def unapply(tree: Tree): Option[(Modifiers, TermName, List[TypeDef], List[List[ValDef]], Tree, Tree)] = tree match {
+ case DefDef(mods, nme.CONSTRUCTOR, tparams, vparamss, tpt, Block(List(expr), Literal(Constant(())))) =>
+ Some((mods, nme.CONSTRUCTOR, tparams, vparamss, tpt, expr))
+ case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ Some((mods, name, tparams, vparamss, tpt, rhs))
+ case _ => None
+ }
+ }
+
+ protected class SyntacticValDefBase(isMutable: Boolean) extends SyntacticValDefExtractor {
+ def modifiers(mods: Modifiers): Modifiers = if (isMutable) mods | MUTABLE else mods
+
+ def apply(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree): ValDef = ValDef(modifiers(mods), name, tpt, rhs)
+
+ def unapply(tree: Tree): Option[(Modifiers, TermName, Tree, Tree)] = tree match {
+ case ValDef(mods, name, tpt, rhs) if mods.hasFlag(MUTABLE) == isMutable =>
+ Some((mods, name, tpt, rhs))
+ case _ =>
+ None
+ }
+ }
+ object SyntacticValDef extends SyntacticValDefBase(isMutable = false)
+ object SyntacticVarDef extends SyntacticValDefBase(isMutable = true)
+
+ object SyntacticAssign extends SyntacticAssignExtractor {
+ def apply(lhs: Tree, rhs: Tree): Tree = gen.mkAssign(lhs, rhs)
+ def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
+ case Assign(lhs, rhs) => Some((lhs, rhs))
+ case AssignOrNamedArg(lhs, rhs) => Some((lhs, rhs))
+ case Apply(Select(fn, nme.update), args :+ rhs) => Some((atPos(fn.pos)(Apply(fn, args)), rhs))
+ case _ => None
+ }
+ }
+
+ def UnliftListElementwise[T](unliftable: Unliftable[T]) = new UnliftListElementwise[T] {
+ def unapply(lst: List[Tree]): Option[List[T]] = {
+ val unlifted = lst.flatMap { unliftable.unapply(_) }
+ if (unlifted.length == lst.length) Some(unlifted) else None
+ }
+ }
+
+ def UnliftListOfListsElementwise[T](unliftable: Unliftable[T]) = new UnliftListOfListsElementwise[T] {
+ def unapply(lst: List[List[Tree]]): Option[List[List[T]]] = {
+ val unlifted = lst.map { l => l.flatMap { unliftable.unapply(_) } }
+ if (unlifted.flatten.length == lst.flatten.length) Some(unlifted) else None
+ }
+ }
+
+ object SyntacticValFrom extends SyntacticValFromExtractor {
+ def apply(pat: Tree, rhs: Tree): Tree = gen.ValFrom(pat, gen.mkCheckIfRefutable(pat, rhs))
+ def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
+ case gen.ValFrom(pat, UnCheckIfRefutable(pat1, rhs1)) if pat.equalsStructure(pat1) =>
+ Some((pat, rhs1))
+ case gen.ValFrom(pat, rhs) =>
+ Some((pat, rhs))
+ case _ => None
+ }
+ }
+
+ object SyntacticValEq extends SyntacticValEqExtractor {
+ def apply(pat: Tree, rhs: Tree): Tree = gen.ValEq(pat, rhs)
+ def unapply(tree: Tree): Option[(Tree, Tree)] = gen.ValEq.unapply(tree)
+ }
+
+ object SyntacticFilter extends SyntacticFilterExtractor {
+ def apply(tree: Tree): Tree = gen.Filter(tree)
+ def unapply(tree: Tree): Option[Tree] = gen.Filter.unapply(tree)
+ }
+
+ // If a tree in type position isn't provided by the user (e.g. `tpt` fields of
+ // `ValDef` and `DefDef`, function params etc), then it's going to be parsed as
+ // TypeTree with empty original and empty tpe. This extractor matches such trees
+ // so that one can write q"val x = 2" to match typecheck(q"val x = 2"). Note that
+ // TypeTree() is the only possible representation for empty trees in type positions.
+ // We used to sometimes receive EmptyTree in such cases, but not anymore.
+ object SyntacticEmptyTypeTree extends SyntacticEmptyTypeTreeExtractor {
+ def apply(): TypeTree = self.TypeTree()
+ def unapply(tt: TypeTree): Boolean = tt.original == null || tt.original.isEmpty
+ }
+
+ // match a sequence of desugared `val $pat = $value`
+ protected object UnPatSeq {
+ def unapply(trees: List[Tree]): Option[List[(Tree, Tree)]] = {
+ val imploded = implodePatDefs(trees)
+ val patvalues = imploded.flatMap {
+ case SyntacticPatDef(_, pat, EmptyTree, rhs) => Some((pat, rhs))
+ case ValDef(_, name, SyntacticEmptyTypeTree(), rhs) => Some((Bind(name, self.Ident(nme.WILDCARD)), rhs))
+ case ValDef(_, name, tpt, rhs) => Some((Bind(name, Typed(self.Ident(nme.WILDCARD), tpt)), rhs))
+ case _ => None
+ }
+ if (patvalues.length == imploded.length) Some(patvalues) else None
+ }
+ }
+
+ // implode multiple-statement desugaring of pattern definitions
+ // into single-statement valdefs with nme.QUASIQUOTE_PAT_DEF name
+ object implodePatDefs extends Transformer {
+ override def transform(tree: Tree) = tree match {
+ case templ: Template => deriveTemplate(templ)(transformStats)
+ case block: Block =>
+ val Block(init, last) = block
+ Block(transformStats(init), transform(last)).copyAttrs(block)
+ case ValDef(mods, name1, SyntacticEmptyTypeTree(), Match(MaybeTyped(MaybeUnchecked(value), tpt), CaseDef(pat, EmptyTree, Ident(name2)) :: Nil))
+ if name1 == name2 =>
+ ValDef(mods, nme.QUASIQUOTE_PAT_DEF, Typed(pat, tpt), transform(value))
+ case _ =>
+ super.transform(tree)
+ }
+ def transformStats(trees: List[Tree]): List[Tree] = trees match {
+ case Nil => Nil
+ case ValDef(mods, _, SyntacticEmptyTypeTree(), Match(MaybeTyped(MaybeUnchecked(value), tpt), CaseDef(pat, EmptyTree, SyntacticTuple(ids)) :: Nil)) :: tail
+ if mods.hasFlag(SYNTHETIC) && mods.hasFlag(ARTIFACT) =>
+ ids match {
+ case Nil =>
+ ValDef(NoMods, nme.QUASIQUOTE_PAT_DEF, Typed(pat, tpt), transform(value)) :: transformStats(tail)
+ case _ =>
+ val mods = tail.take(1).head.asInstanceOf[ValDef].mods
+ ValDef(mods, nme.QUASIQUOTE_PAT_DEF, Typed(pat, tpt), transform(value)) :: transformStats(tail.drop(ids.length))
+ }
+ case other :: tail =>
+ transform(other) :: transformStats(tail)
+ }
+ def apply(tree: Tree) = transform(tree)
+ def apply(trees: List[Tree]) = transformStats(trees)
+ }
+
+ object SyntacticPatDef extends SyntacticPatDefExtractor {
+ def apply(mods: Modifiers, pat: Tree, tpt: Tree, rhs: Tree): List[ValDef] = tpt match {
+ case SyntacticEmptyTypeTree() => gen.mkPatDef(mods, pat, rhs)
+ case _ => gen.mkPatDef(mods, Typed(pat, tpt), rhs)
+ }
+ def unapply(tree: Tree): Option[(Modifiers, Tree, Tree, Tree)] = tree match {
+ case ValDef(mods, nme.QUASIQUOTE_PAT_DEF, Typed(pat, tpt), rhs) => Some((mods, pat, tpt, rhs))
+ case _ => None
+ }
+ }
+
+ // match a sequence of desugared `val $pat = $value` with a tuple in the end
+ protected object UnPatSeqWithRes {
+ def unapply(tree: Tree): Option[(List[(Tree, Tree)], List[Tree])] = tree match {
+ case SyntacticBlock(UnPatSeq(trees) :+ SyntacticTuple(elems)) => Some((trees, elems))
+ case _ => None
+ }
+ }
+
+ // undo gen.mkSyntheticParam
+ protected object UnSyntheticParam {
+ def unapply(tree: Tree): Option[TermName] = tree match {
+ case ValDef(mods, name, _, EmptyTree)
+ if mods.hasFlag(SYNTHETIC) && mods.hasFlag(PARAM) =>
+ Some(name)
+ case _ => None
+ }
+ }
+
+ // undo gen.mkVisitor
+ protected object UnVisitor {
+ def unapply(tree: Tree): Option[(TermName, List[CaseDef])] = tree match {
+ case Function(UnSyntheticParam(x1) :: Nil, Match(MaybeUnchecked(Ident(x2)), cases))
+ if x1 == x2 =>
+ Some((x1, cases))
+ case _ => None
+ }
+ }
+
+ // undo gen.mkFor:makeClosure
+ protected object UnClosure {
+ def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
+ case Function(ValDef(Modifiers(PARAM, _, _), name, tpt, EmptyTree) :: Nil, body) =>
+ tpt match {
+ case SyntacticEmptyTypeTree() => Some((Bind(name, self.Ident(nme.WILDCARD)), body))
+ case _ => Some((Bind(name, Typed(self.Ident(nme.WILDCARD), tpt)), body))
+ }
+ case UnVisitor(_, CaseDef(pat, EmptyTree, body) :: Nil) =>
+ Some((pat, body))
+ case _ => None
+ }
+ }
+
+ // match call to either withFilter or filter
+ protected object FilterCall {
+ def unapply(tree: Tree): Option[(Tree,Tree)] = tree match {
+ case Apply(Select(obj, nme.withFilter | nme.filter), arg :: Nil) =>
+ Some(obj, arg)
+ case _ => None
+ }
+ }
+
+ // transform a chain of withFilter calls into a sequence of for filters
+ protected object UnFilter {
+ def unapply(tree: Tree): Some[(Tree, List[Tree])] = tree match {
+ case UnCheckIfRefutable(_, _) =>
+ Some((tree, Nil))
+ case FilterCall(UnFilter(rhs, rest), UnClosure(_, test)) =>
+ Some((rhs, rest :+ SyntacticFilter(test)))
+ case _ =>
+ Some((tree, Nil))
+ }
+ }
+
+ // undo gen.mkCheckIfRefutable
+ protected object UnCheckIfRefutable {
+ def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
+ case FilterCall(rhs, UnVisitor(name,
+ CaseDef(pat, EmptyTree, Literal(Constant(true))) ::
+ CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false))) :: Nil))
+ if name.toString.contains(nme.CHECK_IF_REFUTABLE_STRING) =>
+ Some((pat, rhs))
+ case _ => None
+ }
+ }
+
+ // undo gen.mkFor:makeCombination accounting for possible extra implicit argument
+ protected class UnForCombination(name: TermName) {
+ def unapply(tree: Tree) = tree match {
+ case SyntacticApplied(SyntacticTypeApplied(sel @ Select(lhs, meth), _), (f :: Nil) :: Nil)
+ if name == meth && sel.hasAttachment[ForAttachment.type] =>
+ Some(lhs, f)
+ case SyntacticApplied(SyntacticTypeApplied(sel @ Select(lhs, meth), _), (f :: Nil) :: _ :: Nil)
+ if name == meth && sel.hasAttachment[ForAttachment.type] =>
+ Some(lhs, f)
+ case _ => None
+ }
+ }
+ protected object UnMap extends UnForCombination(nme.map)
+ protected object UnForeach extends UnForCombination(nme.foreach)
+ protected object UnFlatMap extends UnForCombination(nme.flatMap)
+
+ // undo desugaring done in gen.mkFor
+ protected object UnFor {
+ def unapply(tree: Tree): Option[(List[Tree], Tree)] = {
+ val interm = tree match {
+ case UnFlatMap(UnFilter(rhs, filters), UnClosure(pat, UnFor(rest, body))) =>
+ Some(((pat, rhs), filters ::: rest, body))
+ case UnForeach(UnFilter(rhs, filters), UnClosure(pat, UnFor(rest, body))) =>
+ Some(((pat, rhs), filters ::: rest, body))
+ case UnMap(UnFilter(rhs, filters), UnClosure(pat, cbody)) =>
+ Some(((pat, rhs), filters, gen.Yield(cbody)))
+ case UnForeach(UnFilter(rhs, filters), UnClosure(pat, cbody)) =>
+ Some(((pat, rhs), filters, cbody))
+ case _ => None
+ }
+ interm.flatMap {
+ case ((Bind(_, SyntacticTuple(_)) | SyntacticTuple(_),
+ UnFor(SyntacticValFrom(pat, rhs) :: innerRest, gen.Yield(UnPatSeqWithRes(pats, elems2)))),
+ outerRest, fbody) =>
+ val valeqs = pats.map { case (pat, rhs) => SyntacticValEq(pat, rhs) }
+ Some((SyntacticValFrom(pat, rhs) :: innerRest ::: valeqs ::: outerRest, fbody))
+ case ((pat, rhs), filters, body) =>
+ Some((SyntacticValFrom(pat, rhs) :: filters, body))
+ }
+ }
+ }
+
+ // check that enumerators are valid
+ protected def mkEnumerators(enums: List[Tree]): List[Tree] = {
+ require(enums.nonEmpty, "enumerators can't be empty")
+ enums.head match {
+ case SyntacticValFrom(_, _) =>
+ case t => throw new IllegalArgumentException(s"$t is not a valid fist enumerator of for loop")
+ }
+ enums.tail.foreach {
+ case SyntacticValEq(_, _) | SyntacticValFrom(_, _) | SyntacticFilter(_) =>
+ case t => throw new IllegalArgumentException(s"$t is not a valid representation of a for loop enumerator")
+ }
+ enums
+ }
+
+ object SyntacticFor extends SyntacticForExtractor {
+ def apply(enums: List[Tree], body: Tree): Tree = gen.mkFor(mkEnumerators(enums), body)
+ def unapply(tree: Tree) = tree match {
+ case UnFor(enums, gen.Yield(body)) => None
+ case UnFor(enums, body) => Some((enums, body))
+ case _ => None
+ }
+ }
+
+ object SyntacticForYield extends SyntacticForExtractor {
+ def apply(enums: List[Tree], body: Tree): Tree = gen.mkFor(mkEnumerators(enums), gen.Yield(body))
+ def unapply(tree: Tree) = tree match {
+ case UnFor(enums, gen.Yield(body)) => Some((enums, body))
+ case _ => None
+ }
+ }
+
+ // use typetree's original instead of typetree itself
+ protected object MaybeTypeTreeOriginal {
+ def unapply(tree: Tree): Some[Tree] = tree match {
+ case tt: TypeTree => Some(tt.original)
+ case _ => Some(tree)
+ }
+ }
+
+ // drop potential extra call to .apply
+ protected object MaybeSelectApply {
+ def unapply(tree: Tree): Some[Tree] = tree match {
+ case Select(f, nme.apply) => Some(f)
+ case other => Some(other)
+ }
+ }
+
+ // drop potential @scala.unchecked annotation
+ protected object MaybeUnchecked {
+ def unapply(tree: Tree): Some[Tree] = tree match {
+ case Annotated(SyntacticNew(Nil, ScalaDot(tpnme.unchecked) :: Nil, noSelfType, Nil), annottee) =>
+ Some(annottee)
+ case Typed(annottee, MaybeTypeTreeOriginal(
+ Annotated(SyntacticNew(Nil, ScalaDot(tpnme.unchecked) :: Nil, noSelfType, Nil), _))) =>
+ Some(annottee)
+ case annottee => Some(annottee)
+ }
+ }
+
+ protected object MaybeTyped {
+ def unapply(tree: Tree): Some[(Tree, Tree)] = tree match {
+ case Typed(v, tpt) => Some((v, tpt))
+ case v => Some((v, SyntacticEmptyTypeTree()))
+ }
+ }
+
+ protected def mkCases(cases: List[Tree]): List[CaseDef] = cases.map {
+ case c: CaseDef => c
+ case tree => throw new IllegalArgumentException("$tree is not valid representation of pattern match case")
+ }
+
+ object SyntacticPartialFunction extends SyntacticPartialFunctionExtractor {
+ def apply(cases: List[Tree]): Match = Match(EmptyTree, mkCases(cases))
+ def unapply(tree: Tree): Option[List[CaseDef]] = tree match {
+ case Match(EmptyTree, cases) => Some(cases)
+ case Typed(
+ Block(
+ List(ClassDef(clsMods, tpnme.ANON_FUN_NAME, Nil, Template(
+ List(abspf: TypeTree, ser: TypeTree), noSelfType, List(
+ DefDef(_, nme.CONSTRUCTOR, _, _, _, _),
+ DefDef(_, nme.applyOrElse, _, _, _,
+ Match(_, cases :+
+ CaseDef(Bind(nme.DEFAULT_CASE, Ident(nme.WILDCARD)), _, _))),
+ DefDef(_, nme.isDefinedAt, _, _, _, _))))),
+ Apply(Select(New(Ident(tpnme.ANON_FUN_NAME)), termNames.CONSTRUCTOR), List())),
+ pf: TypeTree)
+ if pf.tpe != null && pf.tpe.typeSymbol.eq(PartialFunctionClass) &&
+ abspf.tpe != null && abspf.tpe.typeSymbol.eq(AbstractPartialFunctionClass) &&
+ ser.tpe != null && ser.tpe.typeSymbol.eq(SerializableClass) &&
+ clsMods.hasFlag(FINAL) && clsMods.hasFlag(SYNTHETIC) =>
+ Some(cases)
+ case _ => None
+ }
+ }
+
+ object SyntacticMatch extends SyntacticMatchExtractor {
+ def apply(scrutinee: Tree, cases: List[Tree]) = {
+ require(scrutinee.nonEmpty, "match's scrutinee may not be empty")
+ Match(scrutinee, mkCases(cases))
+ }
+
+ def unapply(tree: Match): Option[(Tree, List[CaseDef])] = tree match {
+ case Match(scrutinee, cases) if scrutinee.nonEmpty => Some((scrutinee, cases))
+ case _ => None
+ }
+ }
+
+ object SyntacticTry extends SyntacticTryExtractor {
+ def apply(block: Tree, catches: List[Tree], finalizer: Tree) = Try(block, mkCases(catches), finalizer)
+ def unapply(tree: Try): Option[(Tree, List[CaseDef], Tree)] = Try.unapply(tree)
+ }
+
+ object SyntacticTermIdent extends SyntacticTermIdentExtractor {
+ def apply(name: TermName, isBackquoted: Boolean): Ident = {
+ val id = self.Ident(name)
+ if (isBackquoted) id updateAttachment BackquotedIdentifierAttachment
+ id
+ }
+ def unapply(id: Ident): Option[(TermName, Boolean)] = id.name match {
+ case name: TermName => Some((name, id.hasAttachment[BackquotedIdentifierAttachment.type]))
+ case _ => None
+ }
+ }
+
+ object SyntacticTypeIdent extends SyntacticTypeIdentExtractor {
+ def apply(name: TypeName): Ident = self.Ident(name)
+ def unapply(tree: Tree): Option[TypeName] = tree match {
+ case MaybeTypeTreeOriginal(Ident(name: TypeName)) => Some(name)
+ case _ => None
+ }
+ }
+
+ /** Facade over Imports and ImportSelectors that lets to structurally
+ * deconstruct/reconstruct them.
+ *
+ * Selectors are represented in the following way:
+ * 1. q"import foo._" <==> q"import foo.${pq"_"}"
+ * 2. q"import foo.bar" <==> q"import foo.${pq"bar"}"
+ * 3. q"import foo.{bar => baz}" <==> q"import foo.${pq"bar -> baz"}"
+ * 4. q"import foo.{bar => _}" <==> q"import foo.${pq"bar -> _"}"
+ *
+ * All names in selectors are TermNames despite the fact ImportSelector
+ * can theoretically contain TypeNames too (but they never do in practice.)
+ */
+ object SyntacticImport extends SyntacticImportExtractor {
+ // construct/deconstruct {_} import selector
+ private object WildcardSelector {
+ def apply(offset: Int): ImportSelector = ImportSelector(nme.WILDCARD, offset, null, -1)
+ def unapply(sel: ImportSelector): Option[Int] = sel match {
+ case ImportSelector(nme.WILDCARD, offset, null, -1) => Some(offset)
+ case _ => None
+ }
+ }
+
+ // construct/deconstruct {foo} import selector
+ private object NameSelector {
+ def apply(name: TermName, offset: Int): ImportSelector = ImportSelector(name, offset, name, offset)
+ def unapply(sel: ImportSelector): Option[(TermName, Int)] = sel match {
+ case ImportSelector(name1, offset1, name2, offset2) if name1 == name2 && offset1 == offset2 =>
+ Some((name1.toTermName, offset1))
+ case _ =>
+ None
+ }
+ }
+
+ // construct/deconstruct {foo => bar} import selector
+ private object RenameSelector {
+ def apply(name1: TermName, offset1: Int, name2: TermName, offset2: Int): ImportSelector =
+ ImportSelector(name1, offset1, name2, offset2)
+ def unapply(sel: ImportSelector): Option[(TermName, Int, TermName, Int)] = sel match {
+ case ImportSelector(_, _, null | nme.WILDCARD, _) =>
+ None
+ case ImportSelector(name1, offset1, name2, offset2) if name1 != name2 =>
+ Some((name1.toTermName, offset1, name2.toTermName, offset2))
+ case _ =>
+ None
+ }
+ }
+
+ // construct/deconstruct {foo => _} import selector
+ private object UnimportSelector {
+ def apply(name: TermName, offset: Int): ImportSelector =
+ ImportSelector(name, offset, nme.WILDCARD, -1)
+ def unapply(sel: ImportSelector): Option[(TermName, Int)] = sel match {
+ case ImportSelector(name, offset, nme.WILDCARD, _) => Some((name.toTermName, offset))
+ case _ => None
+ }
+ }
+
+ // represent {_} import selector as pq"_"
+ private object WildcardSelectorRepr {
+ def apply(pos: Position): Tree = atPos(pos)(self.Ident(nme.WILDCARD))
+ def unapply(tree: Tree): Option[Position] = tree match {
+ case self.Ident(nme.WILDCARD) => Some(tree.pos)
+ case _ => None
+ }
+ }
+
+ // represent {foo} import selector as pq"foo"
+ private object NameSelectorRepr {
+ def apply(name: TermName, pos: Position): Tree = atPos(pos)(Bind(name, WildcardSelectorRepr(pos)))
+ def unapply(tree: Tree): Option[(TermName, Position)] = tree match {
+ case Bind(name, WildcardSelectorRepr(_)) => Some((name.toTermName, tree.pos))
+ case _ => None
+ }
+ }
+
+ // pq"left -> right"
+ private object Arrow {
+ def apply(left: Tree, right: Tree): Apply =
+ Apply(self.Ident(nme.MINGT), left :: right :: Nil)
+ def unapply(tree: Apply): Option[(Tree, Tree)] = tree match {
+ case Apply(self.Ident(nme.MINGT), left :: right :: Nil) => Some((left, right))
+ case _ => None
+ }
+ }
+
+ // represent {foo => bar} import selector as pq"foo -> bar"
+ private object RenameSelectorRepr {
+ def apply(name1: TermName, pos1: Position, name2: TermName, pos2: Position): Tree = {
+ val left = NameSelectorRepr(name1, pos1)
+ val right = NameSelectorRepr(name2, pos2)
+ atPos(wrappingPos(left :: right :: Nil))(Arrow(left, right))
+ }
+ def unapply(tree: Tree): Option[(TermName, Position, TermName, Position)] = tree match {
+ case Arrow(NameSelectorRepr(name1, pos1), NameSelectorRepr(name2, pos2)) =>
+ Some((name1.toTermName, pos1, name2.toTermName, pos2))
+ case _ =>
+ None
+ }
+ }
+
+ // represent {foo => _} import selector as pq"foo -> _"
+ private object UnimportSelectorRepr {
+ def apply(name: TermName, pos: Position): Tree =
+ atPos(pos)(Arrow(NameSelectorRepr(name, pos), WildcardSelectorRepr(pos)))
+ def unapply(tree: Tree): Option[(TermName, Position)] = tree match {
+ case Arrow(NameSelectorRepr(name, pos), WildcardSelectorRepr(_)) =>
+ Some((name, pos))
+ case _ =>
+ None
+ }
+ }
+
+ private def derivedPos(t: Tree, offset: Int): Position =
+ if (t.pos == NoPosition) NoPosition else t.pos.withPoint(offset)
+
+ private def derivedOffset(pos: Position): Int =
+ if (pos == NoPosition) -1 else pos.point
+
+ def apply(expr: Tree, selectors: List[Tree]): Import = {
+ val importSelectors = selectors.map {
+ case WildcardSelectorRepr(pos) => WildcardSelector(derivedOffset(pos))
+ case NameSelectorRepr(name, pos) => NameSelector(name, derivedOffset(pos))
+ case RenameSelectorRepr(name1, pos1, name2, pos2) => RenameSelector(name1, derivedOffset(pos1), name2, derivedOffset(pos2))
+ case UnimportSelectorRepr(name, pos) => UnimportSelector(name, derivedOffset(pos))
+ case tree => throw new IllegalArgumentException(s"${showRaw(tree)} doesn't correspond to import selector")
+ }
+ Import(expr, importSelectors)
+ }
+
+ def unapply(imp: Import): Some[(Tree, List[Tree])] = {
+ val selectors = imp.selectors.map {
+ case WildcardSelector(offset) => WildcardSelectorRepr(derivedPos(imp, offset))
+ case NameSelector(name, offset) => NameSelectorRepr(name, derivedPos(imp, offset))
+ case RenameSelector(name1, offset1, name2, offset2) => RenameSelectorRepr(name1, derivedPos(imp, offset1), name2, derivedPos(imp, offset2))
+ case UnimportSelector(name, offset) => UnimportSelectorRepr(name, derivedPos(imp, offset))
+ }
+ Some((imp.expr, selectors))
+ }
+ }
+
+ object SyntacticSelectType extends SyntacticSelectTypeExtractor {
+ def apply(qual: Tree, name: TypeName): Select = Select(qual, name)
+ def unapply(tree: Tree): Option[(Tree, TypeName)] = tree match {
+ case MaybeTypeTreeOriginal(Select(qual, name: TypeName)) => Some((qual, name))
+ case _ => None
+ }
+ }
+
+ object SyntacticSelectTerm extends SyntacticSelectTermExtractor {
+ def apply(qual: Tree, name: TermName): Select = Select(qual, name)
+ def unapply(tree: Tree): Option[(Tree, TermName)] = tree match {
+ case Select(qual, name: TermName) => Some((qual, name))
+ case _ => None
+ }
+ }
+
+ object SyntacticCompoundType extends SyntacticCompoundTypeExtractor {
+ def apply(parents: List[Tree], defns: List[Tree]) =
+ CompoundTypeTree(Template(gen.mkParents(NoMods, parents), noSelfType, defns))
+ def unapply(tree: Tree): Option[(List[Tree], List[Tree])] = tree match {
+ case MaybeTypeTreeOriginal(CompoundTypeTree(Template(parents, _, defns))) =>
+ Some((parents, defns))
+ case _ =>
+ None
+ }
+ }
+
+ object SyntacticSingletonType extends SyntacitcSingletonTypeExtractor {
+ def apply(ref: Tree): SingletonTypeTree = SingletonTypeTree(ref)
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ case MaybeTypeTreeOriginal(SingletonTypeTree(ref)) =>
+ Some(ref)
+ case _ =>
+ None
+ }
+ }
+
+ object SyntacticTypeProjection extends SyntacticTypeProjectionExtractor {
+ def apply(qual: Tree, name: TypeName): SelectFromTypeTree =
+ SelectFromTypeTree(qual, name)
+ def unapply(tree: Tree): Option[(Tree, TypeName)] = tree match {
+ case MaybeTypeTreeOriginal(SelectFromTypeTree(qual, name)) =>
+ Some((qual, name))
+ case _ =>
+ None
+ }
+ }
+
+ object SyntacticAnnotatedType extends SyntacticAnnotatedTypeExtractor {
+ def apply(tpt: Tree, annot: Tree): Annotated =
+ Annotated(annot, tpt)
+ def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
+ case MaybeTypeTreeOriginal(Annotated(annot, tpt)) =>
+ Some((tpt, annot))
+ case _ =>
+ None
+ }
+ }
+
+ object SyntacticExistentialType extends SyntacticExistentialTypeExtractor {
+ def apply(tpt: Tree, where: List[Tree]): ExistentialTypeTree =
+ ExistentialTypeTree(tpt, where.map {
+ case md: MemberDef => md
+ case tree => throw new IllegalArgumentException("$tree is not legal forSome definition")
+ })
+ def unapply(tree: Tree): Option[(Tree, List[MemberDef])] = tree match {
+ case MaybeTypeTreeOriginal(ExistentialTypeTree(tpt, where)) =>
+ Some((tpt, where))
+ case _ =>
+ None
+ }
+ }
+ }
+
+ val build = new ReificationSupportImpl
+}
diff --git a/src/reflect/scala/reflect/internal/Required.scala b/src/reflect/scala/reflect/internal/Required.scala
index 842491d56d..009bc39d4c 100644
--- a/src/reflect/scala/reflect/internal/Required.scala
+++ b/src/reflect/scala/reflect/internal/Required.scala
@@ -1,15 +1,16 @@
-package scala.reflect
+package scala
+package reflect
package internal
import settings.MutableSettings
trait Required { self: SymbolTable =>
-
def picklerPhase: Phase
- def settings: MutableSettings
+ def erasurePhase: Phase
- def forInteractive: Boolean
+ def settings: MutableSettings
- def forScaladoc: Boolean
+ @deprecated("Interactive is implemented with a custom Global; this flag is ignored", "2.11.0") def forInteractive = false
+ @deprecated("Scaladoc is implemented with a custom Global; this flag is ignored", "2.11.0") def forScaladoc = false
}
diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala
index ab3b9b7ed7..103f885ad4 100644
--- a/src/reflect/scala/reflect/internal/Scopes.scala
+++ b/src/reflect/scala/reflect/internal/Scopes.scala
@@ -3,11 +3,22 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
+import scala.annotation.tailrec
+
trait Scopes extends api.Scopes { self: SymbolTable =>
+ /** An ADT to represent the results of symbol name lookups.
+ */
+ sealed trait NameLookup { def symbol: Symbol ; def isSuccess = false }
+ case class LookupSucceeded(qualifier: Tree, symbol: Symbol) extends NameLookup { override def isSuccess = true }
+ case class LookupAmbiguous(msg: String) extends NameLookup { def symbol = NoSymbol }
+ case class LookupInaccessible(symbol: Symbol, msg: String) extends NameLookup
+ case object LookupNotFound extends NameLookup { def symbol = NoSymbol }
+
class ScopeEntry(val sym: Symbol, val owner: Scope) {
/** the next entry in the hash bucket
*/
@@ -17,15 +28,11 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
*/
var next: ScopeEntry = null
+ def depth = owner.nestingLevel
override def hashCode(): Int = sym.name.start
- override def toString(): String = sym.toString()
+ override def toString() = s"$sym (depth=$depth)"
}
- /**
- * @param sym ...
- * @param owner ...
- * @return ...
- */
private def newScopeEntry(sym: Symbol, owner: Scope): ScopeEntry = {
val e = new ScopeEntry(sym, owner)
e.next = owner.elems
@@ -41,26 +48,26 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
* This is necessary because when run from reflection every scope needs to have a
* SynchronizedScope as mixin.
*/
- class Scope protected[Scopes] (initElems: ScopeEntry = null, initFingerPrints: Long = 0L) extends ScopeApi with MemberScopeApi {
-
- protected[Scopes] def this(base: Scope) = {
- this(base.elems)
- nestinglevel = base.nestinglevel + 1
- }
+ class Scope protected[Scopes]() extends ScopeApi with MemberScopeApi {
- private[scala] var elems: ScopeEntry = initElems
+ private[scala] var elems: ScopeEntry = _
/** The number of times this scope is nested in another
*/
- private var nestinglevel = 0
+ private[Scopes] var nestinglevel = 0
/** the hash table
*/
- private var hashtable: Array[ScopeEntry] = null
+ private[Scopes] var hashtable: Array[ScopeEntry] = null
/** a cache for all elements, to be used by symbol iterator.
*/
private var elemsCache: List[Symbol] = null
+ private var cachedSize = -1
+ private def flushElemsCache() {
+ elemsCache = null
+ cachedSize = -1
+ }
/** size and mask of hash tables
* todo: make hashtables grow?
@@ -72,8 +79,6 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
*/
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: _*)
@@ -82,6 +87,12 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
/** the number of entries in this scope */
override def size: Int = {
+ if (cachedSize < 0)
+ cachedSize = directSize
+
+ cachedSize
+ }
+ private def directSize: Int = {
var s = 0
var e = elems
while (e ne null) {
@@ -92,11 +103,9 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
}
/** enter a scope entry
- *
- * @param e ...
*/
protected def enterEntry(e: ScopeEntry) {
- elemsCache = null
+ flushElemsCache()
if (hashtable ne null)
enterInHash(e)
else if (size >= MIN_HASH)
@@ -110,8 +119,6 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
}
/** enter a symbol
- *
- * @param sym ...
*/
def enter[T <: Symbol](sym: T): T = {
enterEntry(newScopeEntry(sym, this))
@@ -119,14 +126,18 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
}
/** 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)
}
+ def enterIfNew[T <: Symbol](sym: T): T = {
+ val existing = lookupEntry(sym.name)
+ if (existing == null) enter(sym)
+ else existing.sym.asInstanceOf[T]
+ }
+
private def createHash() {
hashtable = new Array[ScopeEntry](HASHSIZE)
enterAllInHash(elems)
@@ -175,8 +186,6 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
}
/** remove entry
- *
- * @param e ...
*/
def unlink(e: ScopeEntry) {
if (elems == e) {
@@ -192,30 +201,64 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
if (e1 == e) {
hashtable(index) = e.tail
} else {
- while (e1.tail != e) e1 = e1.tail;
+ while (e1.tail != e) e1 = e1.tail
e1.tail = e.tail
}
}
- elemsCache = null
+ flushElemsCache()
}
/** remove symbol */
def unlink(sym: Symbol) {
var e = lookupEntry(sym.name)
while (e ne null) {
- if (e.sym == sym) unlink(e);
+ if (e.sym == sym) unlink(e)
e = lookupNextEntry(e)
}
}
- /** lookup a symbol
- *
- * @param name ...
- * @return ...
+ /** Lookup a module or a class, filtering out matching names in scope
+ * which do not match that requirement.
+ */
+ def lookupModule(name: Name): Symbol = findSymbol(lookupAll(name.toTermName))(_.isModule)
+ def lookupClass(name: Name): Symbol = findSymbol(lookupAll(name.toTypeName))(_.isClass)
+
+ /** True if the name exists in this scope, false otherwise. */
+ def containsName(name: Name) = lookupEntry(name) != null
+
+ /** Lookup a symbol.
*/
def lookup(name: Name): Symbol = {
val e = lookupEntry(name)
- if (e eq null) NoSymbol else e.sym
+ if (e eq null) NoSymbol
+ else if (lookupNextEntry(e) eq null) e.sym
+ else {
+ // We shouldn't get here: until now this method was picking a random
+ // symbol when there was more than one with the name, so this should
+ // only be called knowing that there are 0-1 symbols of interest. So, we
+ // can safely return an overloaded symbol rather than throwing away the
+ // rest of them. Most likely we still break, but at least we will break
+ // in an understandable fashion (unexpectedly overloaded symbol) rather
+ // than a non-deterministic bizarre one (see any bug involving overloads
+ // in package objects.)
+ val alts = lookupAll(name).toList
+ def alts_s = alts map (s => s.defString) mkString " <and> "
+ devWarning(s"scope lookup of $name found multiple symbols: $alts_s")
+ // FIXME - how is one supposed to create an overloaded symbol without
+ // knowing the correct owner? Using the symbol owner is not correct;
+ // say for instance this is List's scope and the symbols are its three
+ // mkString members. Those symbols are owned by TraversableLike, which
+ // is no more meaningful an owner than NoSymbol given that we're in
+ // List. Maybe it makes no difference who owns the overloaded symbol, in
+ // which case let's establish that and have a canonical creation method.
+ //
+ // FIXME - a similar question for prefix, although there are more
+ // clues from the symbols on that one, as implemented here. In general
+ // the distinct list is one type and lub becomes the identity.
+ // val prefix = lub(alts map (_.info.prefix) distinct)
+ // Now using NoSymbol and NoPrefix always to avoid forcing info (SI-6664)
+ NoSymbol.newOverloaded(NoPrefix, alts)
+ }
}
/** Returns an iterator yielding every symbol with given name in this scope.
@@ -223,7 +266,20 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
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 }
+ def next(): Symbol = try e.sym finally e = lookupNextEntry(e)
+ }
+
+ def lookupAllEntries(name: Name): Iterator[ScopeEntry] = new Iterator[ScopeEntry] {
+ var e = lookupEntry(name)
+ def hasNext: Boolean = e ne null
+ def next(): ScopeEntry = try e finally e = lookupNextEntry(e)
+ }
+
+ def lookupUnshadowedEntries(name: Name): Iterator[ScopeEntry] = {
+ lookupEntry(name) match {
+ case null => Iterator.empty
+ case e => lookupAllEntries(name) filter (e1 => (e eq e1) || (e.depth == e1.depth && e.sym != e1.sym))
+ }
}
/** lookup a symbol entry matching given name.
@@ -257,20 +313,47 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
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);
+ do { e = e.next } while ((e ne null) && e.sym.name != entry.sym.name)
e
}
+ /** TODO - we can test this more efficiently than checking isSubScope
+ * in both directions. However the size test might be enough to quickly
+ * rule out most failures.
+ */
+ def isSameScope(other: Scope) = (
+ (size == other.size) // optimization - size is cached
+ && (this isSubScope other)
+ && (other isSubScope this)
+ )
+
+ def isSubScope(other: Scope) = {
+ def scopeContainsSym(sym: Symbol): Boolean = {
+ @tailrec def entryContainsSym(e: ScopeEntry): Boolean = e match {
+ case null => false
+ case _ =>
+ val comparableInfo = sym.info.substThis(sym.owner, e.sym.owner)
+ (e.sym.info =:= comparableInfo) || entryContainsSym(lookupNextEntry(e))
+ }
+ entryContainsSym(this lookupEntry sym.name)
+ }
+ other.toList forall scopeContainsSym
+ }
+
/** 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 symbols: List[Symbol] = Nil
+ var count = 0
var e = elems
while ((e ne null) && e.owner == this) {
- elemsCache = e.sym :: elemsCache
+ count += 1
+ symbols ::= e.sym
e = e.next
}
+ elemsCache = symbols
+ cachedSize = count
}
elemsCache
}
@@ -287,37 +370,17 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
*/
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
-
- @deprecated("Use `toList.reverse` instead", "2.10.0")
+ override def filterNot(p: Symbol => Boolean): Scope = (
+ if (toList exists p) newScopeWith(toList filterNot p: _*)
+ else this
+ )
+ override def filter(p: Symbol => Boolean): Scope = (
+ if (toList forall p) this
+ else newScopeWith(toList filter p: _*)
+ )
+ @deprecated("Use `toList.reverse` instead", "2.10.0") // Used in SBT 0.12.4
def reverse: List[Symbol] = toList.reverse
override def mkString(start: String, sep: String, end: String) =
@@ -365,7 +428,14 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
}
/** Create a new scope nested in another one with which it shares its elements */
- def newNestedScope(outer: Scope): Scope = new Scope(outer)
+ final def newNestedScope(outer: Scope): Scope = {
+ val nested = newScope // not `new Scope`, we must allow the runtime reflection universe to mixin SynchronizedScopes!
+ nested.elems = outer.elems
+ nested.nestinglevel = outer.nestinglevel + 1
+ if (outer.hashtable ne null)
+ nested.hashtable = java.util.Arrays.copyOf(outer.hashtable, outer.hashtable.length)
+ nested
+ }
/** Create a new scope with given initial elements */
def newScopeWith(elems: Symbol*): Scope = {
@@ -396,6 +466,4 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
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
index 539d19140c..614e71b597 100644
--- a/src/reflect/scala/reflect/internal/StdAttachments.scala
+++ b/src/reflect/scala/reflect/internal/StdAttachments.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package internal
trait StdAttachments {
@@ -13,6 +14,7 @@ trait StdAttachments {
def setAttachments(attachments: scala.reflect.macros.Attachments { type Pos = Position }): this.type = { rawatt = attachments; this }
def updateAttachment[T: ClassTag](attachment: T): this.type = { rawatt = rawatt.update(attachment); this }
def removeAttachment[T: ClassTag]: this.type = { rawatt = rawatt.remove[T]; this }
+ def hasAttachment[T: ClassTag]: Boolean = rawatt.contains[T]
// cannot be final due to SynchronizedSymbols
def pos: Position = rawatt.pos
@@ -20,9 +22,15 @@ trait StdAttachments {
def setPos(newpos: Position): this.type = { pos = newpos; this }
}
- /** When present, indicates that the host `Ident` has been created from a backquoted identifier.
- */
- case object BackquotedIdentifierAttachment
+ /** Attachment that knows how to import itself into another universe. */
+ trait ImportableAttachment {
+ def importAttachment(importer: Importer): this.type
+ }
+
+ /** Attachment that doesn't contain any reflection artificats and can be imported as-is. */
+ trait PlainAttachment extends ImportableAttachment {
+ def importAttachment(importer: Importer): this.type = this
+ }
/** Stores the trees that give rise to a refined type to be used in reification.
* Unfortunately typed `CompoundTypeTree` is lacking essential info, and the reifier cannot use `CompoundTypeTree.tpe`.
@@ -30,47 +38,18 @@ trait StdAttachments {
*/
case class CompoundTypeTreeOriginalAttachment(parents: List[Tree], stats: List[Tree])
- /** Is added by the macro engine to the results of macro expansions.
- * Stores the original expandee as it entered the `macroExpand` function.
+ /** When present, indicates that the host `Ident` has been created from a backquoted identifier.
*/
- case class MacroExpansionAttachment(original: Tree)
+ case object BackquotedIdentifierAttachment extends PlainAttachment
- /** When present, suppresses macro expansion for the host.
- * This is occasionally necessary, e.g. to prohibit eta-expansion of macros.
- *
- * Does not affect expandability of child nodes, there's context.withMacrosDisabled for that
- * (but think thrice before using that API - see the discussion at https://github.com/scala/scala/pull/1639).
+ /** Identifies trees are either result or intermidiate value of for loop desugaring.
*/
- case object SuppressMacroExpansionAttachment
+ case object ForAttachment extends PlainAttachment
- /** Suppresses macro expansion of the tree by putting SuppressMacroExpansionAttachment on it.
+ /** Identifies unit constants which were inserted by the compiler (e.g. gen.mkBlock)
*/
- def suppressMacroExpansion(tree: Tree) = tree.updateAttachment(SuppressMacroExpansionAttachment)
+ case object SyntheticUnitAttachment extends PlainAttachment
- /** Unsuppresses macro expansion of the tree by removing SuppressMacroExpansionAttachment from it and its children.
- */
- def unsuppressMacroExpansion(tree: Tree): Tree = {
- tree.removeAttachment[SuppressMacroExpansionAttachment.type]
- tree match {
- // see the comment to `isMacroExpansionSuppressed` to learn why we need
- // a special traversal strategy here
- case Apply(fn, _) => unsuppressMacroExpansion(fn)
- case TypeApply(fn, _) => unsuppressMacroExpansion(fn)
- case _ => // do nothing
- }
- tree
- }
-
- /** Determines whether a tree should not be expanded, because someone has put SuppressMacroExpansionAttachment on it or one of its children.
- */
- def isMacroExpansionSuppressed(tree: Tree): Boolean =
- if (tree.attachments.get[SuppressMacroExpansionAttachment.type].isDefined) true
- else tree match {
- // we have to account for the fact that during typechecking an expandee might become wrapped,
- // i.e. surrounded by an inferred implicit argument application or by an inferred type argument application.
- // in that case the expandee itself will no longer be suppressed and we need to look at the core
- case Apply(fn, _) => isMacroExpansionSuppressed(fn)
- case TypeApply(fn, _) => isMacroExpansionSuppressed(fn)
- case _ => false
- }
+ /** Untyped list of subpatterns attached to selector dummy. */
+ case class SubpatternsAttachment(patterns: List[Tree])
}
diff --git a/src/reflect/scala/reflect/internal/StdCreators.scala b/src/reflect/scala/reflect/internal/StdCreators.scala
index 5e5e4f9043..a0084dc95c 100644
--- a/src/reflect/scala/reflect/internal/StdCreators.scala
+++ b/src/reflect/scala/reflect/internal/StdCreators.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package internal
import scala.reflect.api.{TreeCreator, TypeCreator}
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index c3b7f24a9d..6848c357c5 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -3,10 +3,12 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
import java.security.MessageDigest
+import java.util.UUID.randomUUID
import Chars.isOperatorPart
import scala.annotation.switch
import scala.language.implicitConversions
@@ -18,8 +20,6 @@ trait StdNames {
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
@@ -37,11 +37,7 @@ trait StdNames {
kws = kws + result
result
}
- def result: Set[TermName] = {
- val result = kws
- kws = null
- result
- }
+ def result: Set[TermName] = try kws finally kws = null
}
private[reflect] def compactifyName(orig: String): String = compactify(orig)
@@ -57,14 +53,17 @@ trait StdNames {
*
* We obtain the formula:
*
- * FileNameLength = 2*(MaxNameLength / 4) + 2.marker.length + 32 + 6
+ * FileNameLength = 2*(MaxNameLength / 4) + 2.marker.length + 32 + suffixLength
*
- * (+6 for ".class"). MaxNameLength can therefore be computed as follows:
+ * (+suffixLength for ".class" and potential module class suffix that is added *after* this transform).
+ *
+ * MaxNameLength can therefore be computed as follows:
*/
val marker = "$$$$"
+ val maxSuffixLength = "$.class".length + 1 // potential module class suffix and file extension
val MaxNameLength = math.min(
- settings.maxClassfileName.value - 6,
- 2 * (settings.maxClassfileName.value - 6 - 2*marker.length - 32)
+ settings.maxClassfileName.value - maxSuffixLength,
+ 2 * (settings.maxClassfileName.value - maxSuffixLength - 2*marker.length - 32)
)
def toMD5(s: String, edge: Int): String = {
val prefix = s take edge
@@ -93,8 +92,11 @@ trait StdNames {
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 NAME_JOIN_STRING: String = NameTransformer.NAME_JOIN_STRING
+ val MODULE_SUFFIX_STRING: String = NameTransformer.MODULE_SUFFIX_STRING
+ val LOCAL_SUFFIX_STRING: String = NameTransformer.LOCAL_SUFFIX_STRING
+ val TRAIT_SETTER_SEPARATOR_STRING: String = NameTransformer.TRAIT_SETTER_SEPARATOR_STRING
+
val SINGLETON_SUFFIX: String = ".type"
val ANON_CLASS_NAME: NameType = "$anon"
@@ -105,7 +107,6 @@ trait StdNames {
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"
@@ -122,20 +123,17 @@ trait StdNames {
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 WeakTypeTag: NameType = "WeakTypeTag"
- final val TypeTag : NameType = "TypeTag"
- final val Expr: NameType = "Expr"
- final val String: NameType = "String"
+ 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 WeakTypeTag: NameType = "WeakTypeTag"
+ final val TypeTag : NameType = "TypeTag"
+ final val Expr: NameType = "Expr"
+ final val String: NameType = "String"
+ final val StringContext: NameType = "StringContext"
// fictions we use as both types and terms
final val ERROR: NameType = "<error>"
@@ -207,10 +205,11 @@ trait StdNames {
}
abstract class TypeNames extends Keywords with TypeNamesApi {
+ override 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>"
@@ -218,29 +217,45 @@ trait StdNames {
final val WILDCARD_STAR: NameType = "_*"
final val REIFY_TREECREATOR_PREFIX: NameType = "$treecreator"
final val REIFY_TYPECREATOR_PREFIX: NameType = "$typecreator"
+ final val MACRO_BUNDLE_SUFFIX: NameType = "$Bundle"
final val Any: NameType = "Any"
final val AnyVal: NameType = "AnyVal"
- final val ExprApi: NameType = "ExprApi"
+ final val FlagSet: NameType = "FlagSet"
final val Mirror: NameType = "Mirror"
+ final val Modifiers: NameType = "Modifiers"
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 unchecked: NameType = "unchecked"
+ final val api: NameType = "api"
final val Annotation: NameType = "Annotation"
+ final val CaseDef: NameType = "CaseDef"
final val ClassfileAnnotation: NameType = "ClassfileAnnotation"
final val ClassManifest: NameType = "ClassManifest"
final val Enum: NameType = "Enum"
final val Group: NameType = "Group"
+ final val implicitNotFound: NameType = "implicitNotFound"
+ final val Liftable: NameType = "Liftable"
+ final val Unliftable: NameType = "Unliftable"
+ final val Name: NameType = "Name"
final val Tree: NameType = "Tree"
+ final val TermName: NameType = "TermName"
final val Type : NameType = "Type"
- final val TypeTree: NameType = "TypeTree"
+ final val TypeName: NameType = "TypeName"
+ final val TypeDef: NameType = "TypeDef"
+ final val Quasiquote: NameType = "Quasiquote"
+
+ // quasiquote-specific names
+ final val QUASIQUOTE_FUNCTION: NameType = "$quasiquote$function$"
+ final val QUASIQUOTE_MODS: NameType = "$quasiquote$mods$"
+ final val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$"
// Annotation simple names, used in Namer
final val BeanPropertyAnnot: NameType = "BeanProperty"
@@ -250,22 +265,20 @@ trait StdNames {
// 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"
+ final val scala_ : NameType = "scala"
+
def dropSingletonName(name: Name): TypeName = (name dropRight SINGLETON_SUFFIX.length).toTypeName
def singletonName(name: Name): TypeName = (name append SINGLETON_SUFFIX).toTypeName
def implClassName(name: Name): TypeName = (name append IMPL_CLASS_SUFFIX).toTypeName
@@ -273,27 +286,30 @@ trait StdNames {
}
abstract class TermNames extends Keywords with TermNamesApi {
+ override 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$"
+ val BITMAP_PREFIX = "bitmap$"
+ val CHECK_IF_REFUTABLE_STRING = "check$ifrefutable$"
+ val DEFAULT_GETTER_STRING = "$default$"
+ val DEFAULT_GETTER_INIT_STRING = NameTransformer.encode("<init>") + DEFAULT_GETTER_STRING
+ val DO_WHILE_PREFIX = "doWhile$"
+ val EVIDENCE_PARAM_PREFIX = "evidence$"
+ val EXCEPTION_RESULT_PREFIX = "exceptionResult"
+ val EXPAND_SEPARATOR_STRING = "$$"
+ val FRESH_TERM_NAME_PREFIX = "x$"
+ val INTERPRETER_IMPORT_WRAPPER = "$iw"
+ 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 WHILE_PREFIX = "while$"
+ val FRESH_PREFIX = "fresh"
+ val FRESH_SUFFIX = "macro$" // uses a keyword to avoid collisions with mangled names
+ val QUAL_PREFIX = "qual$"
+ val NAMEDARG_PREFIX = "x$"
// Compiler internal names
val ANYname: NameType = "<anyname>"
@@ -301,12 +317,9 @@ trait StdNames {
val DEFAULT_CASE: NameType = "defaultCase$"
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_BUILD_PREFIX: NameType = "$u.internal.reificationSupport."
val UNIVERSE_PREFIX: NameType = "$u."
val UNIVERSE_SHORT: NameType = "$u"
val MIRROR_PREFIX: NameType = "$m."
@@ -316,24 +329,31 @@ trait StdNames {
val REIFY_FREE_THIS_SUFFIX: NameType = "$this"
val REIFY_FREE_VALUE_SUFFIX: NameType = "$value"
val REIFY_SYMDEF_PREFIX: NameType = "symdef$"
+ val QUASIQUOTE_CASE: NameType = "$quasiquote$case$"
+ val QUASIQUOTE_EARLY_DEF: NameType = "$quasiquote$early$def$"
+ val QUASIQUOTE_FILE: String = "<quasiquote>"
+ val QUASIQUOTE_FOR_ENUM: NameType = "$quasiquote$for$enum$"
+ val QUASIQUOTE_NAME_PREFIX: String = "nn$"
+ val QUASIQUOTE_PACKAGE_STAT: NameType = "$quasiquote$package$stat$"
+ val QUASIQUOTE_PARAM: NameType = "$quasiquote$param$"
+ val QUASIQUOTE_PAT_DEF: NameType = "$quasiquote$pat$def$"
+ val QUASIQUOTE_PREFIX: String = "qq$"
+ val QUASIQUOTE_REFINE_STAT: NameType = "$quasiquote$refine$stat$"
+ val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$"
+ val QUASIQUOTE_UNLIFT_HELPER: String = "$quasiquote$unlift$helper$"
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_LOCAL: NameType = OUTER.localName
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 SETTER_SUFFIX: NameType = NameTransformer.SETTER_SUFFIX_STRING
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
@@ -341,7 +361,6 @@ trait StdNames {
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)
@@ -358,33 +377,32 @@ trait StdNames {
)
}
- 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 =
+ private def expandedNameInternal(name: TermName, base: Symbol, separator: String): TermName =
newTermNameCached(base.fullName('$') + separator + name)
+ /** The expanded name of `name` relative to this class `base`
+ */
+ def expandedName(name: TermName, base: Symbol) = expandedNameInternal(name, base, EXPAND_SEPARATOR_STRING)
+
/** 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)
+ def expandedSetterName(name: TermName, base: Symbol) = expandedNameInternal(name, base, TRAIT_SETTER_SEPARATOR_STRING)
- /** If `name` is an expandedName name, the original name.
- * Otherwise `name` itself.
- */
- def originalName(name: Name): Name = name.toString lastIndexOf "$$" match {
- case -1 | 0 => name
- case idx0 =>
+ /** If `name` is an expandedName name, the original (unexpanded) name.
+ * Otherwise `name` itself.
+ * Look backward from the end of the string for "$$", and take the
+ * part of the string after that; but if the string is "$$$" or longer,
+ * be sure to retain the extra dollars.
+ */
+ def unexpandedName(name: Name): Name = name lastIndexOf "$$" match {
+ case 0 | -1 => name
+ case idx0 =>
// Sketchville - We've found $$ but if it's part of $$$ or $$$$
// or something we need to keep the bonus dollars, so e.g. foo$$$outer
// has an original name of $outer.
@@ -394,34 +412,38 @@ trait StdNames {
name drop idx + 2
}
+ @deprecated("Use unexpandedName", "2.11.0") def originalName(name: Name): Name = unexpandedName(name)
+ @deprecated("Use Name#dropModule", "2.11.0") def stripModuleSuffix(name: Name): Name = name.dropModule
+ @deprecated("Use Name#dropLocal", "2.11.0") def localToGetter(name: TermName): TermName = name.dropLocal
+ @deprecated("Use Name#dropLocal", "2.11.0") def dropLocalSuffix(name: Name): TermName = name.dropLocal
+ @deprecated("Use Name#localName", "2.11.0") def getterToLocal(name: TermName): TermName = name.localName
+ @deprecated("Use Name#setterName", "2.11.0") def getterToSetter(name: TermName): TermName = name.setterName
+ @deprecated("Use Name#getterName", "2.11.0") def getterName(name: TermName): TermName = name.getterName
+ @deprecated("Use Name#getterName", "2.11.0") def setterToGetter(name: TermName): TermName = name.getterName
+
+ /**
+ * Convert `Tuple2$mcII` to `Tuple2`, or `T1$sp` to `T1`.
+ */
def unspecializedName(name: Name): Name = (
+ // DUPLICATED LOGIC WITH `splitSpecializedName`
if (name endsWith SPECIALIZED_SUFFIX)
- name.subName(0, name.lastIndexOf('m') - 1)
+ 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")
+ * splitSpecializedName("foo$mIcD$sp") == ('foo', "D", "I")
* }}}
* `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.
+ *
+ * @return (unspecializedName, class tparam specializations, method tparam specializations)
*/
def splitSpecializedName(name: Name): (Name, String, String) =
+ // DUPLICATED LOGIC WITH `unspecializedName`
if (name endsWith SPECIALIZED_SUFFIX) {
val name1 = name dropRight SPECIALIZED_SUFFIX.length
val idxC = name1 lastIndexOf 'c'
@@ -433,51 +455,23 @@ trait StdNames {
} 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)
- }
+ def defaultGetterName(name: Name, pos: Int): TermName = (
+ if (isConstructorName(name))
+ DEFAULT_GETTER_INIT_STRING + pos
+ else
+ name + 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.charAt(pos - 1).isDigit)
- pos -= 1
-
- if (pos <= 0 || pos == name.length || name.charAt(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 defaultGetterToMethod(name: Name): TermName = (
+ if (name startsWith DEFAULT_GETTER_INIT_STRING)
+ nme.CONSTRUCTOR
+ else name indexOf DEFAULT_GETTER_STRING match {
+ case -1 => name.toTermName
+ case idx => name.toTermName take idx
+ }
)
+
def localDummyName(clazz: Symbol): TermName = newTermName(LOCALDUMMY_PREFIX + clazz.name + ">")
def superName(name: Name): TermName = newTermName(SUPER_PREFIX_STRING + name)
@@ -489,8 +483,6 @@ trait StdNames {
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"
@@ -586,115 +578,109 @@ trait StdNames {
val Annotation: NameType = "Annotation"
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 CaseDef: NameType = "CaseDef"
+ val ClassInfoType: NameType = "ClassInfoType"
val ConstantType: NameType = "ConstantType"
val EmptyPackage: NameType = "EmptyPackage"
val EmptyPackageClass: NameType = "EmptyPackageClass"
- val ExistentialTypeTree: NameType = "ExistentialTypeTree"
+ val ExistentialType: NameType = "ExistentialType"
val Flag : NameType = "Flag"
+ val FlagsRepr: NameType = "FlagsRepr"
val Ident: NameType = "Ident"
+ val ImplicitParams: NameType = "ImplicitParams"
val Import: NameType = "Import"
val Literal: NameType = "Literal"
val LiteralAnnotArg: NameType = "LiteralAnnotArg"
+ val MethodType: NameType = "MethodType"
val Modifiers: NameType = "Modifiers"
val NestedAnnotArg: NameType = "NestedAnnotArg"
+ val New: NameType = "New"
val NoFlags: NameType = "NoFlags"
- val NoPrefix: NameType = "NoPrefix"
val NoSymbol: NameType = "NoSymbol"
+ val NoMods: NameType = "NoMods"
val Nothing: NameType = "Nothing"
- val NoType: NameType = "NoType"
val Null: NameType = "Null"
+ val NullaryMethodType: NameType = "NullaryMethodType"
val Object: NameType = "Object"
+ val PolyType: NameType = "PolyType"
+ val RefinedType: NameType = "RefinedType"
val RootPackage: NameType = "RootPackage"
val RootClass: NameType = "RootClass"
val Select: NameType = "Select"
val SelectFromTypeTree: NameType = "SelectFromTypeTree"
- val StringContext: NameType = "StringContext"
+ val SingleType: NameType = "SingleType"
+ val SuperType: NameType = "SuperType"
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 TypeBounds: NameType = "TypeBounds"
val TypeRef: NameType = "TypeRef"
val TypeTree: NameType = "TypeTree"
val UNIT : NameType = "UNIT"
+ val accessor: NameType = "accessor"
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 applyOrElse: NameType = "applyOrElse"
val args : NameType = "args"
- val argv : NameType = "argv"
val arrayClass: NameType = "arrayClass"
- val arrayElementClass: NameType = "arrayElementClass"
- 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 asTerm: NameType = "asTerm"
val asModule: NameType = "asModule"
- val asMethod: NameType = "asMethod"
val asType: NameType = "asType"
- val asClass: NameType = "asClass"
val asInstanceOf_ : NameType = "asInstanceOf"
val asInstanceOf_Ob : NameType = "$asInstanceOf"
- val assert_ : NameType = "assert"
- val assume_ : NameType = "assume"
val box: NameType = "box"
- val build : NameType = "build"
val bytes: NameType = "bytes"
+ val c: NameType = "c"
val canEqual_ : NameType = "canEqual"
- val checkInitialized: NameType = "checkInitialized"
- val ClassManifestFactory: NameType = "ClassManifestFactory"
val classOf: NameType = "classOf"
- val clone_ : NameType = if (forMSIL) "MemberwiseClone" else "clone" // sn.OClone causes checkinit failure
- val conforms: NameType = "conforms"
+ val clone_ : NameType = "clone"
+ val collection: NameType = "collection"
+ val conforms: NameType = "$conforms" // dollar prefix to avoid accidental shadowing
val copy: NameType = "copy"
+ val create: NameType = "create"
val currentMirror: NameType = "currentMirror"
- val definitions: NameType = "definitions"
val delayedInit: NameType = "delayedInit"
val delayedInitArg: NameType = "delayedInit$body"
+ val dollarScope: NameType = "$scope"
val drop: NameType = "drop"
val elem: NameType = "elem"
- val emptyValDef: NameType = "emptyValDef"
+ val noSelfType: NameType = "noSelfType"
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 equals_ : NameType = "equals"
val error: NameType = "error"
- val eval: NameType = "eval"
val ex: NameType = "ex"
val experimental: NameType = "experimental"
val f: NameType = "f"
val false_ : NameType = "false"
val filter: NameType = "filter"
- val finalize_ : NameType = if (forMSIL) "Finalize" else "finalize"
+ val finalize_ : NameType = "finalize"
val find_ : NameType = "find"
- val flagsFromBits : NameType = "flagsFromBits"
val flatMap: NameType = "flatMap"
val foreach: NameType = "foreach"
- val genericArrayOps: NameType = "genericArrayOps"
+ val freshTermName: NameType = "freshTermName"
+ val freshTypeName: NameType = "freshTypeName"
val get: NameType = "get"
- val getOrElse: NameType = "getOrElse"
- val hasNext: NameType = "hasNext"
- val hashCode_ : NameType = if (forMSIL) "GetHashCode" else "hashCode"
+ val hashCode_ : NameType = "hashCode"
val hash_ : NameType = "hash"
- val head: NameType = "head"
- val identity: NameType = "identity"
+ val head : NameType = "head"
+ val immutable: NameType = "immutable"
val implicitly: NameType = "implicitly"
val in: NameType = "in"
- val info: NameType = "info"
+ val internal: NameType = "internal"
val inlinedEquals: NameType = "inlinedEquals"
val isArray: NameType = "isArray"
val isDefinedAt: NameType = "isDefinedAt"
@@ -706,102 +692,140 @@ trait StdNames {
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 ManifestFactory: NameType = "ManifestFactory"
val manifestToTypeTag: NameType = "manifestToTypeTag"
val map: NameType = "map"
val materializeClassTag: NameType = "materializeClassTag"
val materializeWeakTypeTag: NameType = "materializeWeakTypeTag"
val materializeTypeTag: NameType = "materializeTypeTag"
- val mirror : NameType = "mirror"
val moduleClass : NameType = "moduleClass"
- val name: NameType = "name"
+ val mkAnnotation: NameType = "mkAnnotation"
+ val mkEarlyDef: NameType = "mkEarlyDef"
+ val mkIdent: NameType = "mkIdent"
+ val mkPackageStat: NameType = "mkPackageStat"
+ val mkRefineStat: NameType = "mkRefineStat"
+ val mkRefTree: NameType = "mkRefTree"
+ val mkSelect: NameType = "mkSelect"
+ val mkThis: NameType = "mkThis"
+ val mkTypeTree: NameType = "mkTypeTree"
val ne: NameType = "ne"
val newArray: NameType = "newArray"
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 pendingSuperCall: NameType = "pendingSuperCall"
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 reificationSupport : NameType = "reificationSupport"
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 setInfo: NameType = "setInfo"
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 staticPackage : NameType = "staticPackage"
val synchronized_ : NameType = "synchronized"
- val tail: NameType = "tail"
- val `then` : NameType = "then"
+ val ScalaDot: NameType = "ScalaDot"
+ val TermName: NameType = "TermName"
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 toStats: NameType = "toStats"
+ val TopScope: NameType = "TopScope"
+ val toString_ : NameType = "toString"
val toTypeConstructor: NameType = "toTypeConstructor"
val tpe : NameType = "tpe"
val tree : NameType = "tree"
val true_ : NameType = "true"
val typedProductIterator: NameType = "typedProductIterator"
+ val TypeName: NameType = "TypeName"
val typeTagToManifest: NameType = "typeTagToManifest"
val unapply: NameType = "unapply"
val unapplySeq: NameType = "unapplySeq"
val unbox: NameType = "unbox"
val universe: NameType = "universe"
+ val UnliftListElementwise: NameType = "UnliftListElementwise"
+ val UnliftListOfListsElementwise: NameType = "UnliftListOfListsElementwise"
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"
+ val zero: NameType = "zero"
+
+ // quasiquote interpolators:
+ val q: NameType = "q"
+ val tq: NameType = "tq"
+ val cq: NameType = "cq"
+ val pq: NameType = "pq"
+ val fq: NameType = "fq"
+
+ // quasiquote's syntactic combinators
+ val SyntacticAnnotatedType: NameType = "SyntacticAnnotatedType"
+ val SyntacticApplied: NameType = "SyntacticApplied"
+ val SyntacticAppliedType: NameType = "SyntacticAppliedType"
+ val SyntacticAssign: NameType = "SyntacticAssign"
+ val SyntacticBlock: NameType = "SyntacticBlock"
+ val SyntacticClassDef: NameType = "SyntacticClassDef"
+ val SyntacticCompoundType: NameType = "SyntacticCompoundType"
+ val SyntacticDefDef: NameType = "SyntacticDefDef"
+ val SyntacticEmptyTypeTree: NameType = "SyntacticEmptyTypeTree"
+ val SyntacticExistentialType: NameType = "SyntacticExistentialType"
+ val SyntacticFilter: NameType = "SyntacticFilter"
+ val SyntacticFor: NameType = "SyntacticFor"
+ val SyntacticForYield: NameType = "SyntacticForYield"
+ val SyntacticFunction: NameType = "SyntacticFunction"
+ val SyntacticFunctionType: NameType = "SyntacticFunctionType"
+ val SyntacticImport: NameType = "SyntacticImport"
+ val SyntacticMatch: NameType = "SyntacticMatch"
+ val SyntacticNew: NameType = "SyntacticNew"
+ val SyntacticObjectDef: NameType = "SyntacticObjectDef"
+ val SyntacticPackageObjectDef: NameType = "SyntacticPackageObjectDef"
+ val SyntacticPartialFunction: NameType = "SyntacticPartialFunction"
+ val SyntacticPatDef: NameType = "SyntacticPatDef"
+ val SyntacticSelectTerm: NameType = "SyntacticSelectTerm"
+ val SyntacticSelectType: NameType = "SyntacticSelectType"
+ val SyntacticSingletonType: NameType = "SyntacticSingletonType"
+ val SyntacticTermIdent: NameType = "SyntacticTermIdent"
+ val SyntacticTraitDef: NameType = "SyntacticTraitDef"
+ val SyntacticTry: NameType = "SyntacticTry"
+ val SyntacticTuple: NameType = "SyntacticTuple"
+ val SyntacticTupleType: NameType = "SyntacticTupleType"
+ val SyntacticTypeApplied: NameType = "SyntacticTypeApplied"
+ val SyntacticTypeIdent: NameType = "SyntacticTypeIdent"
+ val SyntacticTypeProjection: NameType = "SyntacticTypeProjection"
+ val SyntacticValDef: NameType = "SyntacticValDef"
+ val SyntacticValEq: NameType = "SyntacticValEq"
+ val SyntacticValFrom: NameType = "SyntacticValFrom"
+ val SyntacticVarDef: NameType = "SyntacticVarDef"
// unencoded operators
object raw {
- final val AMP : NameType = "&"
final val BANG : NameType = "!"
final val BAR : NameType = "|"
final val DOLLAR: NameType = "$"
@@ -810,7 +834,6 @@ trait StdNames {
final val MINUS: NameType = "-"
final val NE: NameType = "!="
final val PLUS : NameType = "+"
- final val SLASH: NameType = "/"
final val STAR : NameType = "*"
final val TILDE: NameType = "~"
@@ -834,29 +857,33 @@ trait StdNames {
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("||")
+ val ADD = encode("+")
+ val AND = encode("&")
+ val ASR = encode(">>")
+ val CONS = encode("::")
+ val COLONPLUS = 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 MINGT = 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 PLUSPLUS = encode("++")
+ val SUB = MINUS // ... as does SUB with PLUS
+ val XOR = encode("^")
+ val ZAND = encode("&&")
+ val ZOR = encode("||")
// unary operators
val UNARY_~ = encode("unary_~")
@@ -866,14 +893,7 @@ trait StdNames {
// 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"
@@ -998,6 +1018,8 @@ trait StdNames {
val BITMAP_CHECKINIT_TRANSIENT: NameType = BITMAP_PREFIX + "inittrans$" // initialization bitmap for transient checkinit values
}
+ lazy val typeNames: tpnme.type = tpnme
+
object tpnme extends TypeNames { }
/** For fully qualified type names.
@@ -1005,7 +1027,6 @@ trait StdNames {
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$.
@@ -1019,17 +1040,14 @@ trait StdNames {
val javanme = nme.javaKeywords
- object nme extends TermNames {
-
- def isModuleVarName(name: Name): Boolean =
- stripAnonNumberSuffix(name) endsWith MODULE_VAR_SUFFIX
+ lazy val termNames: nme.type = nme
+ object nme extends TermNames {
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
@@ -1037,58 +1055,9 @@ trait StdNames {
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 val stringToTermName = null
- protected val stringToTypeName = null
- 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 {
@@ -1148,7 +1117,11 @@ trait StdNames {
final val keywords = kw.result
}
- private abstract class JavaNames extends SymbolNames {
+ sealed abstract class SymbolNames {
+ protected val stringToTermName = null
+ protected val stringToTypeName = null
+ protected implicit def createNameType(s: String): TypeName = newTypeNameCached(s)
+
final val BoxedBoolean: TypeName = "java.lang.Boolean"
final val BoxedByte: TypeName = "java.lang.Byte"
final val BoxedCharacter: TypeName = "java.lang.Character"
@@ -1158,25 +1131,18 @@ trait StdNames {
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,
@@ -1190,52 +1156,5 @@ trait StdNames {
)
}
- 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
+ lazy val sn: SymbolNames = new SymbolNames { }
}
diff --git a/src/reflect/scala/reflect/internal/SymbolPairs.scala b/src/reflect/scala/reflect/internal/SymbolPairs.scala
new file mode 100644
index 0000000000..c088e8f57c
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/SymbolPairs.scala
@@ -0,0 +1,302 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala
+package reflect
+package internal
+
+import scala.collection.mutable
+import Flags._
+import util.HashSet
+import scala.annotation.tailrec
+
+/** An abstraction for considering symbol pairs.
+ * One of the greatest sources of compiler bugs is that symbols can
+ * trivially lose their prefixes and turn into some completely different
+ * type with the smallest of errors. It is the exception not the rule
+ * that type comparisons are done correctly.
+ *
+ * This offers a small step toward coherence with two abstractions
+ * which come up over and over again:
+ *
+ * RelativeTo: operations relative to a prefix
+ * SymbolPair: two symbols being related somehow, plus the class
+ * in which the relation is being performed
+ *
+ * This is only a start, but it is a start.
+ */
+abstract class SymbolPairs {
+ val global: SymbolTable
+ import global._
+
+ /** Type operations relative to a prefix. All operations work on Symbols,
+ * and the types are the member types of those symbols in the prefix.
+ */
+ class RelativeTo(val prefix: Type) {
+ def this(clazz: Symbol) = this(clazz.thisType)
+ import scala.language.implicitConversions // geez, it even has to hassle me when it's private
+ private implicit def symbolToType(sym: Symbol): Type = prefix memberType sym
+
+ def erasureOf(sym: Symbol): Type = erasure.erasure(sym)(sym: Type)
+ def signature(sym: Symbol): String = sym defStringSeenAs (sym: Type)
+ def erasedSignature(sym: Symbol): String = sym defStringSeenAs erasureOf(sym)
+
+ def isSameType(sym1: Symbol, sym2: Symbol): Boolean = sym1 =:= sym2
+ def isSubType(sym1: Symbol, sym2: Symbol): Boolean = sym1 <:< sym2
+ def isSuperType(sym1: Symbol, sym2: Symbol): Boolean = sym2 <:< sym1
+ def isSameErasure(sym1: Symbol, sym2: Symbol): Boolean = erasureOf(sym1) =:= erasureOf(sym2)
+ def matches(sym1: Symbol, sym2: Symbol): Boolean = (sym1: Type) matches (sym2: Type)
+
+ override def toString = s"RelativeTo($prefix)"
+ }
+
+ /** Are types tp1 and tp2 equivalent seen from the perspective
+ * of `baseClass`? For instance List[Int] and Seq[Int] are =:=
+ * when viewed from IterableClass.
+ */
+ def sameInBaseClass(baseClass: Symbol)(tp1: Type, tp2: Type) =
+ (tp1 baseType baseClass) =:= (tp2 baseType baseClass)
+
+ case class SymbolPair(base: Symbol, low: Symbol, high: Symbol) {
+ def pos = if (low.owner == base) low.pos else if (high.owner == base) high.pos else base.pos
+ def self: Type = base.thisType
+ def rootType: Type = base.thisType
+
+ def lowType: Type = self memberType low
+ def lowErased: Type = erasure.specialErasure(base)(low.tpe)
+ def lowClassBound: Type = classBoundAsSeen(low.tpe.typeSymbol)
+
+ def highType: Type = self memberType high
+ def highInfo: Type = self memberInfo high
+ def highErased: Type = erasure.specialErasure(base)(high.tpe)
+ def highClassBound: Type = classBoundAsSeen(high.tpe.typeSymbol)
+
+ def isErroneous = low.tpe.isErroneous || high.tpe.isErroneous
+ def sameKind = sameLength(low.typeParams, high.typeParams)
+
+ private def classBoundAsSeen(tsym: Symbol) =
+ tsym.classBound.asSeenFrom(rootType, tsym.owner)
+
+ private def memberDefString(sym: Symbol, where: Boolean) = {
+ val def_s = (
+ if (sym.isConstructor) s"$sym: ${self memberType sym}"
+ else sym defStringSeenAs (self memberType sym)
+ )
+ def_s + whereString(sym)
+ }
+ /** A string like ' at line 55' if the symbol is defined in the class
+ * under consideration, or ' in trait Foo' if defined elsewhere.
+ */
+ private def whereString(sym: Symbol) =
+ if (sym.owner == base) " at line " + sym.pos.line else sym.locationString
+
+ def lowString = memberDefString(low, where = true)
+ def highString = memberDefString(high, where = true)
+
+ override def toString = sm"""
+ |Cursor(in $base) {
+ | high $highString
+ | erased $highErased
+ | infos ${high.infosString}
+ | low $lowString
+ | erased $lowErased
+ | infos ${low.infosString}
+ |}""".trim
+ }
+
+ /** The cursor class
+ * @param base the base class containing the participating symbols
+ */
+ abstract class Cursor(val base: Symbol) {
+ cursor =>
+
+ final val self = base.thisType // The type relative to which symbols are seen.
+ private val decls = newScope // all the symbols which can take part in a pair.
+ private val size = bases.length
+
+ /** A symbol for which exclude returns true will not appear as
+ * either end of a pair.
+ */
+ protected def exclude(sym: Symbol): Boolean
+
+ /** Does `sym1` match `sym2` such that (sym1, sym2) should be
+ * considered as a (lo, high) pair? Types always match. Term symbols
+ * match if their member types relative to `self` match.
+ */
+ protected def matches(lo: Symbol, high: Symbol): Boolean
+
+ /** The parents and base classes of `base`. Can be refined in subclasses.
+ */
+ protected def parents: List[Type] = base.info.parents
+ protected def bases: List[Symbol] = base.info.baseClasses
+
+ /** An implementation of BitSets as arrays (maybe consider collection.BitSet
+ * for that?) The main purpose of this is to implement
+ * intersectionContainsElement efficiently.
+ */
+ private type BitSet = Array[Int]
+
+ /** A mapping from all base class indices to a bitset
+ * which indicates whether parents are subclasses.
+ *
+ * i \in subParents(j) iff
+ * exists p \in parents, b \in baseClasses:
+ * i = index(p)
+ * j = index(b)
+ * p isSubClass b
+ * p.baseType(b) == self.baseType(b)
+ */
+ private val subParents = new Array[BitSet](size)
+
+ /** A map from baseclasses of <base> to ints, with smaller ints meaning lower in
+ * linearization order. Symbols that are not baseclasses map to -1.
+ */
+ private val index = new mutable.HashMap[Symbol, Int] { override def default(key: Symbol) = -1 }
+
+ /** The scope entries that have already been visited as highSymbol
+ * (but may have been excluded via hasCommonParentAsSubclass.)
+ * These will not appear as lowSymbol.
+ */
+ private val visited = HashSet[ScopeEntry]("visited", 64)
+
+ /** Initialization has to run now so decls is populated before
+ * the declaration of curEntry.
+ */
+ init()
+
+ // The current low and high symbols; the high may be null.
+ private[this] var lowSymbol: Symbol = _
+ private[this] var highSymbol: Symbol = _
+
+ // The current entry candidates for low and high symbol.
+ private[this] var curEntry = decls.elems
+ private[this] var nextEntry = curEntry
+
+ // These fields are initially populated with a call to next().
+ next()
+
+ // populate the above data structures
+ private def init() {
+ // Fill `decls` with lower symbols shadowing higher ones
+ def fillDecls(bcs: List[Symbol], deferred: Boolean) {
+ if (!bcs.isEmpty) {
+ fillDecls(bcs.tail, deferred)
+ var e = bcs.head.info.decls.elems
+ while (e ne null) {
+ if (e.sym.initialize.isDeferred == deferred && !exclude(e.sym))
+ decls enter e.sym
+ e = e.next
+ }
+ }
+ }
+ var i = 0
+ for (bc <- bases) {
+ index(bc) = i
+ subParents(i) = new BitSet(size)
+ i += 1
+ }
+ for (p <- parents) {
+ val pIndex = index(p.typeSymbol)
+ if (pIndex >= 0)
+ for (bc <- p.baseClasses ; if sameInBaseClass(bc)(p, self)) {
+ val bcIndex = index(bc)
+ if (bcIndex >= 0)
+ include(subParents(bcIndex), pIndex)
+ }
+ }
+ // first, deferred (this will need to change if we change lookup rules!)
+ fillDecls(bases, deferred = true)
+ // then, concrete.
+ fillDecls(bases, deferred = false)
+ }
+
+ private def include(bs: BitSet, n: Int) {
+ val nshifted = n >> 5
+ val nmask = 1 << (n & 31)
+ bs(nshifted) |= nmask
+ }
+
+ /** Implements `bs1 * bs2 * {0..n} != 0.
+ * Used in hasCommonParentAsSubclass */
+ private def intersectionContainsElementLeq(bs1: BitSet, bs2: BitSet, n: Int): Boolean = {
+ val nshifted = n >> 5
+ val nmask = 1 << (n & 31)
+ var i = 0
+ while (i < nshifted) {
+ if ((bs1(i) & bs2(i)) != 0) return true
+ i += 1
+ }
+ (bs1(nshifted) & bs2(nshifted) & (nmask | nmask - 1)) != 0
+ }
+
+ /** Do `sym1` and `sym2` have a common subclass in `parents`?
+ * In that case we do not follow their pairs.
+ */
+ private def hasCommonParentAsSubclass(sym1: Symbol, sym2: Symbol) = {
+ val index1 = index(sym1.owner)
+ (index1 >= 0) && {
+ val index2 = index(sym2.owner)
+ (index2 >= 0) && {
+ intersectionContainsElementLeq(
+ subParents(index1), subParents(index2), index1 min index2)
+ }
+ }
+ }
+
+ @tailrec private def advanceNextEntry() {
+ if (nextEntry ne null) {
+ nextEntry = decls lookupNextEntry nextEntry
+ if (nextEntry ne null) {
+ val high = nextEntry.sym
+ val isMatch = matches(lowSymbol, high) && { visited addEntry nextEntry ; true } // side-effect visited on all matches
+
+ // skip nextEntry if a class in `parents` is a subclass of the
+ // owners of both low and high.
+ if (isMatch && !hasCommonParentAsSubclass(lowSymbol, high))
+ highSymbol = high
+ else
+ advanceNextEntry()
+ }
+ }
+ }
+ @tailrec private def advanceCurEntry() {
+ if (curEntry ne null) {
+ curEntry = curEntry.next
+ if (curEntry ne null) {
+ if (visited(curEntry) || exclude(curEntry.sym))
+ advanceCurEntry()
+ else
+ nextEntry = curEntry
+ }
+ }
+ }
+
+ /** The `low` and `high` symbol. In the context of overriding pairs,
+ * low == overriding and high == overridden.
+ */
+ def low = lowSymbol
+ def high = highSymbol
+
+ def hasNext = curEntry ne null
+ def currentPair = new SymbolPair(base, low, high)
+ def iterator = new Iterator[SymbolPair] {
+ def hasNext = cursor.hasNext
+ def next() = try cursor.currentPair finally cursor.next()
+ }
+
+ // Note that next is called once during object initialization to
+ // populate the fields tracking the current symbol pair.
+ def next() {
+ if (curEntry ne null) {
+ lowSymbol = curEntry.sym
+ advanceNextEntry() // sets highSymbol
+ if (nextEntry eq null) {
+ advanceCurEntry()
+ next()
+ }
+ }
+ }
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala
index 6ca8900d7c..c76dedbff4 100644
--- a/src/reflect/scala/reflect/internal/SymbolTable.scala
+++ b/src/reflect/scala/reflect/internal/SymbolTable.scala
@@ -3,18 +3,22 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
import scala.annotation.elidable
import scala.collection.{ mutable, immutable }
import util._
+import java.util.concurrent.TimeUnit
+import scala.reflect.internal.{TreeGen => InternalTreeGen}
abstract class SymbolTable extends macros.Universe
with Collections
with Names
with Symbols
with Types
+ with Variances
with Kinds
with ExistentialsAndSkolems
with FlagSets
@@ -37,36 +41,53 @@ abstract class SymbolTable extends macros.Universe
with CapturedVariables
with StdAttachments
with StdCreators
- with BuildUtils
+ with ReificationSupport
+ with PrivateWithin
+ with pickling.Translations
+ with FreshNames
+ with Internals
{
- val gen = new TreeGen { val global: SymbolTable.this.type = SymbolTable.this }
- lazy val treeBuild = gen
+ val gen = new InternalTreeGen { val global: SymbolTable.this.type = SymbolTable.this }
def log(msg: => AnyRef): Unit
+ def deprecationWarning(pos: Position, msg: String): Unit = warning(msg)
def warning(msg: String): Unit = Console.err.println(msg)
+ def inform(msg: String): Unit = Console.err.println(msg)
def globalError(msg: String): Unit = abort(msg)
def abort(msg: String): Nothing = throw new FatalError(supplementErrorMessage(msg))
+ protected def elapsedMessage(msg: String, start: Long) =
+ msg + " in " + (TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start) + "ms"
+
+ def informProgress(msg: String) = if (settings.verbose) inform("[" + msg + "]")
+ def informTime(msg: String, start: Long) = informProgress(elapsedMessage(msg, start))
+
def shouldLogAtThisPhase = false
+ def isPastTyper = false
+ protected def isDeveloper: Boolean = settings.debug
- @deprecated("Give us a reason", "2.10.0")
- def abort(): Nothing = abort("unknown error")
+ @deprecated("Use devWarning if this is really a warning; otherwise use log", "2.11.0")
+ def debugwarn(msg: => String): Unit = devWarning(msg)
/** 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 debuglog(msg: => String): Unit = if (settings.debug) log(msg)
+ def devWarning(msg: => String): Unit = if (isDeveloper) Console.err.println(msg)
def throwableAsString(t: Throwable): String = "" + t
+ def throwableAsString(t: Throwable, maxFrames: Int): String = t.getStackTrace take maxFrames mkString "\n at "
+
+ @inline final def devWarningDumpStack(msg: => String, maxFrames: Int): Unit =
+ devWarning(msg + "\n" + throwableAsString(new Throwable, maxFrames))
/** Prints a stack trace if -Ydebug or equivalent was given, otherwise does nothing. */
- def debugStack(t: Throwable): Unit = debugwarn(throwableAsString(t))
+ def debugStack(t: Throwable): Unit = devWarning(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")))
+ (new Throwable).getStackTrace.drop(2).take(50).mkString("\n")))
result
}
@@ -81,12 +102,33 @@ abstract class SymbolTable extends macros.Universe
result
}
@inline
+ final private[scala] def debuglogResult[T](msg: => String)(result: T): T = {
+ debuglog(msg + ": " + result)
+ result
+ }
+ @inline
+ final private[scala] def devWarningResult[T](msg: => String)(result: T): T = {
+ devWarning(msg + ": " + result)
+ result
+ }
+ @inline
final private[scala] def logResultIf[T](msg: => String, cond: T => Boolean)(result: T): T = {
if (cond(result))
log(msg + ": " + result)
result
}
+ @inline
+ final private[scala] def debuglogResultIf[T](msg: => String, cond: T => Boolean)(result: T): T = {
+ if (cond(result))
+ debuglog(msg + ": " + result)
+
+ result
+ }
+
+ @inline final def findSymbol(xs: TraversableOnce[Symbol])(p: Symbol => Boolean): Symbol = {
+ xs find p getOrElse NoSymbol
+ }
// For too long have we suffered in order to sort NAMES.
// I'm pretty sure there's a reasonable default for that.
@@ -108,17 +150,13 @@ abstract class SymbolTable extends macros.Universe
val global: SymbolTable.this.type = SymbolTable.this
} with util.TraceSymbolActivity
+ val treeInfo: TreeInfo { val global: SymbolTable.this.type }
+
/** Check that the executing thread is the compiler thread. No-op here,
* overridden in interactive.Global. */
@elidable(elidable.WARNING)
def assertCorrectThread() {}
- /** 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).
@@ -139,7 +177,7 @@ abstract class SymbolTable extends macros.Universe
type RunId = Int
final val NoRunId = 0
- // sigh, this has to be public or atPhase doesn't inline.
+ // sigh, this has to be public or enteringPhase doesn't inline.
var phStack: List[Phase] = Nil
private[this] var ph: Phase = NoPhase
private[this] var per = NoPeriod
@@ -182,9 +220,6 @@ abstract class SymbolTable extends macros.Universe
/** 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)
@@ -202,23 +237,37 @@ abstract class SymbolTable extends macros.Universe
p != NoPhase && phase.id > p.id
/** Perform given operation at given phase. */
- @inline final def atPhase[T](ph: Phase)(op: => T): T = {
+ @inline final def enteringPhase[T](ph: Phase)(op: => T): T = {
val saved = pushPhase(ph)
try op
finally popPhase(saved)
}
+ final def findPhaseWithName(phaseName: String): Phase = {
+ var ph = phase
+ while (ph != NoPhase && ph.name != phaseName) {
+ ph = ph.prev
+ }
+ if (ph eq NoPhase) phase else ph
+ }
+ final def enteringPhaseWithName[T](phaseName: String)(body: => T): T = {
+ val phase = findPhaseWithName(phaseName)
+ enteringPhase(phase)(body)
+ }
- /** 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)
+ def slowButSafeEnteringPhase[T](ph: Phase)(op: => T): T = {
+ if (isCompilerUniverse) enteringPhase(ph)(op)
+ else op
+ }
+
+ @inline final def exitingPhase[T](ph: Phase)(op: => T): T = enteringPhase(ph.next)(op)
+ @inline final def enteringPrevPhase[T](op: => T): T = enteringPhase(phase.prev)(op)
- @inline final def atPhaseNotLaterThan[T](target: Phase)(op: => T): T =
- if (isAtPhaseAfter(target)) atPhase(target)(op) else op
+ @inline final def enteringPhaseNotLaterThan[T](target: Phase)(op: => T): T =
+ if (isAtPhaseAfter(target)) enteringPhase(target)(op) else op
+
+ def slowButSafeEnteringPhaseNotLaterThan[T](target: Phase)(op: => T): T =
+ if (isCompilerUniverse) enteringPhaseNotLaterThan(target)(op) else op
final def isValid(period: Period): Boolean =
period != 0 && runId(period) == currentRunId && {
@@ -231,7 +280,7 @@ abstract class SymbolTable extends macros.Universe
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)
@@ -302,27 +351,45 @@ abstract class SymbolTable extends macros.Universe
}
object perRunCaches {
- 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 = WeakHashSet[Clearable]()
+ import java.lang.ref.WeakReference
+ private var caches = List[WeakReference[Clearable]]()
def recordCache[T <: Clearable](cache: T): T = {
- caches += cache
+ caches ::= new WeakReference(cache)
cache
}
def clearAll() = {
debuglog("Clearing " + caches.size + " caches.")
- caches foreach (_.clear)
+ caches foreach (ref => Option(ref.get).foreach(_.clear))
+ caches = caches.filterNot(_.get == null)
}
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]())
+
+ def newAnyRefMap[K <: AnyRef, V]() = recordCache(mutable.AnyRefMap[K, V]())
+ def newGeneric[T](f: => T): () => T = {
+ val NoCached: T = null.asInstanceOf[T]
+ var cached: T = NoCached
+ var cachedRunId = NoRunId
+ recordCache(new Clearable {
+ def clear(): Unit = cached = NoCached
+ })
+ () => {
+ if (currentRunId != cachedRunId || cached == NoCached) {
+ cached = f
+ cachedRunId = currentRunId
+ }
+ cached
+ }
+ }
}
/** The set of all installed infotransformers. */
@@ -339,26 +406,14 @@ abstract class SymbolTable extends macros.Universe
*/
def isCompilerUniverse = false
+ @deprecated("Use enteringPhase", "2.10.0") // Used in SBT 0.12.4
+ @inline final def atPhase[T](ph: Phase)(op: => T): T = enteringPhase(ph)(op)
+
+
/**
* Adds the `sm` String interpolator to a [[scala.StringContext]].
*/
implicit val StringContextStripMarginOps: StringContext => StringContextStripMarginOps = util.StringContextStripMarginOps
-
- def importPrivateWithinFromJavaFlags(sym: Symbol, jflags: Int): Symbol = {
- import ClassfileConstants._
- if ((jflags & (JAVA_ACC_PRIVATE | JAVA_ACC_PROTECTED | JAVA_ACC_PUBLIC)) == 0)
- // See ticket #1687 for an example of when topLevelClass is NoSymbol: it
- // apparently occurs when processing v45.3 bytecode.
- if (sym.enclosingTopLevelClass != NoSymbol)
- sym.privateWithin = sym.enclosingTopLevelClass.owner
-
- // protected in java means package protected. #3946
- if ((jflags & JAVA_ACC_PROTECTED) != 0)
- if (sym.enclosingTopLevelClass != NoSymbol)
- sym.privateWithin = sym.enclosingTopLevelClass.owner
-
- sym
- }
}
object SymbolTableStats {
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 579f7684fd..2ce54d2259 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -3,15 +3,17 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
import scala.collection.{ mutable, immutable }
import scala.collection.mutable.ListBuffer
-import util.Statistics
+import util.{ Statistics, shortClassOfInstance }
import Flags._
import scala.annotation.tailrec
-import scala.reflect.io.AbstractFile
+import scala.reflect.io.{ AbstractFile, NoAbstractFile }
+import Variance._
trait Symbols extends api.Symbols { self: SymbolTable =>
import definitions._
@@ -19,8 +21,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
protected var ids = 0
- val emptySymbolArray = new Array[Symbol](0)
-
protected def nextId() = { ids += 1; ids }
/** Used for deciding in the IDE whether we can interrupt the compiler */
@@ -30,13 +30,13 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
//protected var lockedSyms = scala.collection.immutable.Set[Symbol]()
/** Used to keep track of the recursion depth on locked symbols */
- private var recursionTable = immutable.Map.empty[Symbol, Int]
+ private var _recursionTable = immutable.Map.empty[Symbol, Int]
+ def recursionTable = _recursionTable
+ def recursionTable_=(value: immutable.Map[Symbol, Int]) = _recursionTable = value
- private var nextexid = 0
- protected def freshExistentialName(suffix: String) = {
- nextexid += 1
- newTypeName("_" + nextexid + suffix)
- }
+ private var existentialIds = 0
+ protected def nextExistentialId() = { existentialIds += 1; existentialIds }
+ protected def freshExistentialName(suffix: String) = newTypeName("_" + nextExistentialId() + suffix)
// Set the fields which point companions at one another. Returns the module.
def connectModuleToClass(m: ModuleSymbol, moduleClass: ClassSymbol): ModuleSymbol = {
@@ -55,31 +55,50 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def newFreeTypeSymbol(name: TypeName, flags: Long = 0L, origin: String): FreeTypeSymbol =
new FreeTypeSymbol(name, origin) initFlags flags
- /** Determines whether the given information request should trigger the given symbol's completer.
- * See comments to `Symbol.needsInitialize` for details.
- */
- protected def shouldTriggerCompleter(symbol: Symbol, completer: Type, isFlagRelated: Boolean, mask: Long) =
- completer match {
- case null => false
- case _: FlagAgnosticCompleter => !isFlagRelated
- case _ => abort(s"unsupported completer: $completer of class ${if (completer != null) completer.getClass else null} for symbol ${symbol.fullName}")
- }
-
/** 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 {
+ // 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.)
+ protected def saveOriginalOwner(sym: Symbol) {
+ if (originalOwner contains sym) ()
+ else originalOwner(sym) = sym.rawowner
+ }
+ protected def originalEnclosingMethod(sym: Symbol): Symbol = {
+ if (sym.isMethod || sym == NoSymbol) sym
+ else {
+ val owner = originalOwner.getOrElse(sym, sym.rawowner)
+ if (sym.isLocalDummy) owner.enclClass.primaryConstructor
+ else originalEnclosingMethod(owner)
+ }
+ }
+
+ def symbolOf[T: WeakTypeTag]: TypeSymbol = weakTypeOf[T].typeSymbolDirect.asType
+
+ abstract class SymbolContextApiImpl extends SymbolApi {
this: Symbol =>
+ def isFreeTerm: Boolean = false
+ def asFreeTerm: FreeTermSymbol = throw new ScalaReflectionException(s"$this is not a free term")
+ def isFreeType: Boolean = false
+ def asFreeType: FreeTypeSymbol = throw new ScalaReflectionException(s"$this is not a free type")
+
def isExistential: Boolean = this.isExistentiallyBound
def isParamWithDefault: Boolean = this.hasDefault
+ // `isByNameParam` is only true for a call-by-name parameter of a *method*,
+ // an argument of the primary constructor seen in the class body is excluded by `isValueParameter`
def isByNameParam: Boolean = this.isValueParameter && (this hasFlag BYNAMEPARAM)
def isImplementationArtifact: Boolean = (this hasFlag BRIDGE) || (this hasFlag VBRIDGE) || (this hasFlag ARTIFACT)
def isJava: Boolean = isJavaDefined
def isVal: Boolean = isTerm && !isModule && !isMethod && !isMutable
def isVar: Boolean = isTerm && !isModule && !isMethod && !isLazy && isMutable
+ def isAbstract: Boolean = isAbstractClass || isDeferred || isAbstractType
+ def isPrivateThis = (this hasFlag PRIVATE) && (this hasFlag LOCAL)
+ def isProtectedThis = (this hasFlag PROTECTED) && (this hasFlag LOCAL)
def newNestedSymbol(name: Name, pos: Position, newFlags: Long, isClass: Boolean): Symbol = name match {
case n: TermName => newTermSymbol(n, pos, newFlags)
@@ -87,27 +106,70 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
def knownDirectSubclasses = {
- if (!isCompilerUniverse && needsInitialize(isFlagRelated = false, mask = 0)) initialize
+ // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method.
+ if (!isCompilerUniverse && !isThreadsafe(purpose = AllOps)) initialize
children
}
+ def selfType = {
+ // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method.
+ if (!isCompilerUniverse && !isThreadsafe(purpose = AllOps)) initialize
+ typeOfThis
+ }
+
def baseClasses = info.baseClasses
def module = sourceModule
def thisPrefix: Type = thisType
- def selfType: Type = typeOfThis
- def typeSignature: Type = { fullyInitializeSymbol(this); info }
- def typeSignatureIn(site: Type): Type = { fullyInitializeSymbol(this); site memberInfo this }
+ def superPrefix(supertpe: Type): Type = SuperType(thisType, supertpe)
+
+ // These two methods used to call fullyInitializeSymbol on `this`.
+ //
+ // The only positive effect of that is, to the best of my knowledge, convenient printing
+ // (if you print a signature of the symbol that's not fully initialized,
+ // you might end up with weird <?>'s in value/type params)
+ //
+ // Another effect is obviously full initialization of that symbol,
+ // but that one shouldn't be necessary from the public API standpoint,
+ // because everything that matters auto-initializes at runtime,
+ // and auto-initialization at compile-time is anyway dubious
+ // (I've had spurious cyclic refs caused by calling typeSignature
+ // that initialized parent, which was in the middle of initialization).
+ //
+ // Given that and also given the pressure of being uniform with info and infoIn,
+ // I've removed calls to fullyInitializeSymbol from typeSignature and typeSignatureIn,
+ // injected fullyInitializeSymbol in showDecl, and injected fullyInitializeType in runtime Type.toString
+ // (the latter will make things a bit harder to debug in runtime universe, because
+ // toString might now very rarely cause cyclic references, but we also have showRaw that doesn't do initialization).
+ //
+ // Auto-initialization in runtime Type.toString is one of the examples of why a cake-based design
+ // isn't a very good idea for reflection API. Sometimes we want to same pretty name for both a compiler-facing
+ // and a user-facing API that should have different behaviors (other examples here include isPackage, isCaseClass, etc).
+ // Within a cake it's fundamentally impossible to achieve that.
+ def typeSignature: Type = info
+ def typeSignatureIn(site: Type): Type = site memberInfo this
def toType: Type = tpe
def toTypeIn(site: Type): Type = site.memberType(this)
def toTypeConstructor: Type = typeConstructor
- def setTypeSignature(tpe: Type): this.type = { setInfo(tpe); this }
def setAnnotations(annots: AnnotationInfo*): this.type = { setAnnotations(annots.toList); this }
def getter: Symbol = getter(owner)
def setter: Symbol = setter(owner)
+
+ def companion: Symbol = {
+ if (isModule && !isPackage) companionSymbol
+ else if (isModuleClass && !isPackageClass) sourceModule.companionSymbol
+ else if (isClass && !isModuleClass && !isPackageClass) companionSymbol
+ else NoSymbol
+ }
+
+ def infoIn(site: Type): Type = typeSignatureIn(site)
+ def overrides: List[Symbol] = allOverriddenSymbols
+ def paramLists: List[List[Symbol]] = paramss
}
+ private[reflect] case class SymbolKind(accurate: String, sanitized: String, abbreviation: String)
+
/** The class for all symbols */
abstract class Symbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: Name)
extends SymbolContextApiImpl
@@ -115,6 +177,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
with Annotatable[Symbol]
with Attachable {
+ // makes sure that all symbols that runtime reflection deals with are synchronized
+ private def isSynchronized = this.isInstanceOf[scala.reflect.runtime.SynchronizedSymbols#SynchronizedSymbol]
+ private def isAprioriThreadsafe = isThreadsafe(AllOps)
+ assert(isCompilerUniverse || isSynchronized || isAprioriThreadsafe, s"unsafe symbol $initName (child of $initOwner) in runtime reflection universe")
+
type AccessBoundaryType = Symbol
type AnnotationType = AnnotationInfo
@@ -128,13 +195,16 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def name: NameType
def name_=(n: Name): Unit = {
if (shouldLogAtThisPhase) {
- val msg = s"Renaming $fullLocationString to $n"
+ def msg = s"In $owner, renaming $name -> $n"
if (isSpecialized) debuglog(msg) else log(msg)
}
}
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
+ // Syncnote: need not be protected, as only assignment happens in owner_=, which is not exposed to api
+ // The null check is for NoSymbol, which can't pass a reference to itself to the constructor and also
+ // can't call owner_= due to an assertion it contains.
+ private[this] var _rawowner = if (initOwner eq null) this else initOwner
private[this] var _rawflags: Long = _
def rawowner = _rawowner
@@ -171,13 +241,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def debugFlagString: String = flagString(AllFlags)
/** String representation of symbol's variance */
- def varianceString: String =
- if (variance == 1) "+"
- else if (variance == -1) "-"
- else ""
+ def varianceString: String = variance.symbolicString
override def flagMask =
- if (settings.debug.value && !isAbstractType) AllFlags
+ if (settings.debug && !isAbstractType) AllFlags
else if (owner.isRefinementClass) ExplicitFlags & ~OVERRIDE
else ExplicitFlags
@@ -186,10 +253,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
if (isGADTSkolem) " (this is a GADT skolem)"
else ""
- def shortSymbolClass = getClass.getName.split('.').last.stripPrefix("Symbols$")
+ def shortSymbolClass = shortClassOfInstance(this)
def symbolCreationString: String = (
"%s%25s | %-40s | %s".format(
- if (settings.uniqid.value) "%06d | ".format(id) else "",
+ if (settings.uniqid) "%06d | ".format(id) else "",
shortSymbolClass,
name.decode + " in " + owner,
rawFlagString
@@ -221,7 +288,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** Static constructor with info set. */
def newStaticConstructor(pos: Position): MethodSymbol =
- newConstructor(pos, STATIC) setInfo UnitClass.tpe
+ newConstructor(pos, STATIC) setInfo UnitTpe
/** Instance constructor with info set. */
def newClassConstructor(pos: Position): MethodSymbol =
@@ -249,20 +316,29 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def newImport(pos: Position): TermSymbol =
newTermSymbol(nme.IMPORT, pos)
+ def newModuleVarSymbol(accessor: Symbol): TermSymbol = {
+ val newName = nme.moduleVarName(accessor.name.toTermName)
+ val newFlags = MODULEVAR | ( if (this.isClass) PrivateLocal | SYNTHETIC else 0 )
+ val newInfo = accessor.tpe.finalResultType
+ val mval = newVariable(newName, accessor.pos.focus, newFlags.toLong) addAnnotation VolatileAttr
+
+ if (this.isClass)
+ mval setInfoAndEnter newInfo
+ else
+ mval setInfo newInfo
+ }
+
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, flags0: FlagSet): (ModuleSymbol, ClassSymbol) = {
val flags = flags0 | MODULE
- val m = newModuleSymbol(name, pos, flags)
+ val m = newModuleSymbol(name.toTermName, pos, flags)
val c = newModuleClass(name.toTypeName, pos, flags & 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]
@@ -325,11 +401,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
() => { cnt += 1; nme.syntheticParamName(cnt) }
}
- /** Synthetic value parameters when parameter symbols are not available
- */
- final def newSyntheticValueParamss(argtypess: List[List[Type]]): List[List[TermSymbol]] =
- argtypess map (xs => newSyntheticValueParams(xs, freshNamer))
-
/** Synthetic value parameters when parameter symbols are not available.
* Calling this method multiple times will re-use the same parameter names.
*/
@@ -345,16 +416,20 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def newSyntheticValueParam(argtype: Type, name: TermName = nme.syntheticParamName(1)): TermSymbol =
newValueParameter(name, owner.pos.focus, SYNTHETIC) setInfo argtype
- 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)
+ def newExistentialSkolem(basis: Symbol, origin: AnyRef): TypeSkolem =
+ newExistentialSkolem(basis.name.toTypeName, basis.info, basis.flags, basis.pos, origin)
+
+ /** Create a new existential type skolem with this symbol its owner, and the given other properties.
+ */
+ def newExistentialSkolem(name: TypeName, info: Type, flags: Long, pos: Position, origin: AnyRef): TypeSkolem = {
+ val skolem = newTypeSkolemSymbol(name.toTypeName, origin, pos, (flags | EXISTENTIAL) & ~PARAM)
+ skolem setInfo (info cloneInfo skolem)
}
// don't test directly -- use isGADTSkolem
@@ -409,14 +484,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
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)
@@ -432,23 +499,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
case _ => new StubTermSymbol(this, name.toTermName, missingMessage)
}
- @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.
@@ -532,14 +582,12 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
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
def isInvariant = !isCovariant && !isContravariant
/** Qualities of Terms, always false for TypeSymbols.
@@ -551,6 +599,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def isConstructor = false
def isEarlyInitialized = false
def isGetter = false
+ def isDefaultGetter = false
def isLocalDummy = false
def isMixinConstructor = false
def isOverloaded = false
@@ -559,7 +608,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def isValue = false
def isValueParameter = false
def isVariable = false
- override def hasDefault = false
def isTermMacro = false
/** Qualities of MethodSymbols, always false for TypeSymbols
@@ -589,27 +637,75 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
def isEffectiveRoot = false
+ /** Can this symbol only be subclassed by bottom classes? This is assessed
+ * to be the case if it is final, and any type parameters are invariant.
+ */
+ def hasOnlyBottomSubclasses = {
+ def loop(tparams: List[Symbol]): Boolean = tparams match {
+ case Nil => true
+ case x :: xs => x.variance.isInvariant && loop(xs)
+ }
+ isClass && isFinal && loop(typeParams)
+ }
+
final def isLazyAccessor = isLazy && lazyAccessor != NoSymbol
- final def isOverridableMember = !(isClass || isEffectivelyFinal) && (this ne NoSymbol) && owner.isClass
+ final def isOverridableMember = !(isClass || isEffectivelyFinal) && safeOwner.isClass
/** Does this symbol denote a wrapper created by the repl? */
final def isInterpreterWrapper = (
(this hasFlag MODULE)
- && owner.isPackageClass
+ && isTopLevel
&& nme.isReplWrapperName(name)
)
+
+ /** In our current architecture, symbols for top-level classes and modules
+ * are created as dummies. Package symbols just call newClass(name) or newModule(name) and
+ * consider their job done.
+ *
+ * In order for such a dummy to provide meaningful info (e.g. a list of its members),
+ * it needs to go through unpickling. Unpickling is a process of reading Scala metadata
+ * from ScalaSignature annotations and assigning it to symbols and types.
+ *
+ * A single unpickling session takes a top-level class or module, parses the ScalaSignature annotation
+ * and then reads metadata for the unpicklee, its companion (if any) and all their members recursively
+ * (i.e. the pickle not only contains info about directly nested classes/modules, but also about
+ * classes/modules nested into those and so on).
+ *
+ * Unpickling is triggered automatically whenever info (info in compiler parlance) is called.
+ * This happens because package symbols assign completer thunks to the dummies they create.
+ * Therefore metadata loading happens lazily and transparently.
+ *
+ * Almost transparently. Unfortunately metadata isn't limited to just signatures (i.e. lists of members).
+ * It also includes flags (which determine e.g. whether a class is sealed or not), annotations and privateWithin.
+ * This gives rise to unpleasant effects like in SI-6277, when a flag test called on an uninitialize symbol
+ * produces incorrect results.
+ *
+ * One might think that the solution is simple: automatically call the completer
+ * whenever one needs flags, annotations and privateWithin - just like it's done for info.
+ * Unfortunately, this leads to weird crashes in scalac, and currently we can't attempt
+ * to fix the core of the compiler risk stability a few weeks before the final release.
+ * upd. Haha, "a few weeks before the final release". This surely sounds familiar :)
+ *
+ * However we do need to fix this for runtime reflection, since this idionsynchrazy is not something
+ * we'd like to expose to reflection users. Therefore a proposed solution is to check whether we're in a
+ * runtime reflection universe, and if yes and if we've not yet loaded the requested info, then to commence initialization.
+ */
final def getFlag(mask: Long): Long = {
- if (!isCompilerUniverse && needsInitialize(isFlagRelated = true, mask = mask)) initialize
+ if (!isCompilerUniverse && !isThreadsafe(purpose = FlagOps(mask))) initialize
flags & mask
}
/** Does symbol have ANY flag in `mask` set? */
final def hasFlag(mask: Long): Boolean = {
- if (!isCompilerUniverse && needsInitialize(isFlagRelated = true, mask = mask)) initialize
+ // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method.
+ if (!isCompilerUniverse && !isThreadsafe(purpose = FlagOps(mask))) initialize
(flags & mask) != 0
}
+ def hasFlag(mask: Int): Boolean = hasFlag(mask.toLong)
+
/** Does symbol have ALL the flags in `mask` set? */
final def hasAllFlags(mask: Long): Boolean = {
- if (!isCompilerUniverse && needsInitialize(isFlagRelated = true, mask = mask)) initialize
+ // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method.
+ if (!isCompilerUniverse && !isThreadsafe(purpose = FlagOps(mask))) initialize
(flags & mask) == mask
}
@@ -642,11 +738,32 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def hasGetter = isTerm && nme.isLocalName(name)
+ /** A little explanation for this confusing situation.
+ * Nested modules which have no static owner when ModuleDefs
+ * are eliminated (refchecks) are given the lateMETHOD flag,
+ * which makes them appear as methods after refchecks.
+ * Here's an example where one can see all four of FF FT TF TT
+ * for (isStatic, isMethod) at various phases.
+ *
+ * trait A1 { case class Quux() }
+ * object A2 extends A1 { object Flax }
+ * // -- namer object Quux in trait A1
+ * // -M flatten object Quux in trait A1
+ * // S- flatten object Flax in object A2
+ * // -M posterasure object Quux in trait A1
+ * // -M jvm object Quux in trait A1
+ * // SM jvm object Quux in object A2
+ *
+ * So "isModuleNotMethod" exists not for its achievement in
+ * brevity, but to encapsulate the relevant condition.
+ */
+ def isModuleNotMethod = isModule && !isMethod
+ def isStaticModule = isModuleNotMethod && isStatic
+
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
+ final def isErroneous = isError || isInitialized && tpe_*.isErroneous
def isHigherOrderTypeParameter = owner.isTypeParameterOrSkolem
@@ -658,7 +775,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
info.firstParent.typeSymbol == AnyValClass && !isPrimitiveValueClass
final def isMethodWithExtension =
- isMethod && owner.isDerivedValueClass && !isParamAccessor && !isConstructor && !hasFlag(SUPERACCESSOR) && !isTermMacro
+ isMethod && owner.isDerivedValueClass && !isParamAccessor && !isConstructor && !hasFlag(SUPERACCESSOR) && !isMacro
final def isAnonymousFunction = isSynthetic && (name containsName tpnme.ANON_FUN_NAME)
final def isDefinedInPackage = effectiveOwner.isPackageClass
@@ -715,10 +832,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
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 isSerializable = info.baseClasses.exists(p => p == SerializableClass || p == JavaSerializableClass)
def hasBridgeAnnotation = hasAnnotation(BridgeClass)
def isDeprecated = hasAnnotation(DeprecatedAttr)
def deprecationMessage = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 0)
@@ -728,14 +842,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
= hasAnnotation(DeprecatedInheritanceAttr)
def deprecatedInheritanceMessage
= getAnnotation(DeprecatedInheritanceAttr) flatMap (_ stringArg 0)
- def deprecatedInheritanceVersion
- = getAnnotation(DeprecatedInheritanceAttr) flatMap (_ stringArg 1)
def hasDeprecatedOverridingAnnotation
= hasAnnotation(DeprecatedOverridingAttr)
def deprecatedOverridingMessage
= getAnnotation(DeprecatedOverridingAttr) flatMap (_ stringArg 0)
- def deprecatedOverridingVersion
- = getAnnotation(DeprecatedOverridingAttr) flatMap (_ stringArg 1)
// !!! 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
@@ -753,19 +863,17 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def compileTimeOnlyMessage = getAnnotation(CompileTimeOnlyAttr) flatMap (_ stringArg 0)
/** Is this symbol an accessor method for outer? */
- final def isOuterAccessor = {
- hasFlag(STABLE | ARTIFACT) &&
- originalName == nme.OUTER
- }
+ final def isOuterAccessor = hasFlag(STABLE | ARTIFACT) && (unexpandedName == nme.OUTER)
/** Is this symbol an accessor method for outer? */
- final def isOuterField = {
- hasFlag(ARTIFACT) &&
- originalName == nme.OUTER_LOCAL
- }
+ final def isOuterField = isArtifact && (unexpandedName == nme.OUTER_LOCAL)
- /** Does this symbol denote a stable value? */
- def isStable = false
+ /** Does this symbol denote a stable value, ignoring volatility?
+ *
+ * Stability and volatility are checked separately to allow volatile paths in patterns that amount to equality checks. SI-6815
+ */
+ final def isStable = isTerm && !isMutable && !(hasFlag(BYNAMEPARAM)) && (!isMethod || hasStableFlag)
+ final def hasVolatileType = tpe.isVolatile && !hasAnnotation(uncheckedStableClass)
/** Does this symbol denote the primary constructor of its enclosing class? */
final def isPrimaryConstructor =
@@ -776,9 +884,14 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
isConstructor && !isPrimaryConstructor
/** Is this symbol a synthetic apply or unapply method in a companion object of a case class? */
+ // xeno-by: why this obscure use of the CASE flag? why not simply compare name with nme.apply and nme.unapply?
final def isCaseApplyOrUnapply =
isMethod && isCase && isSynthetic
+ /** Is this symbol a synthetic copy method in a case class? */
+ final def isCaseCopy =
+ isMethod && owner.isCase && isSynthetic && name == nme.copy
+
/** Is this symbol a trait which needs an implementation class? */
final def needsImplClass = (
isTrait
@@ -815,26 +928,40 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def isStaticOwner: Boolean =
isPackageClass || isModuleClass && isStatic
- def isTopLevelModule = hasFlag(MODULE) && owner.isPackageClass
+ /** A helper function for isEffectivelyFinal. */
+ private def isNotOverridden = (
+ owner.isClass && (
+ owner.isEffectivelyFinal
+ || owner.isSealed && owner.children.forall(c => c.isEffectivelyFinal && (overridingSymbol(c) == NoSymbol))
+ )
+ )
/** 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)
+ || isModuleOrModuleClass && (isTopLevel || !settings.overrideObjects)
|| isTerm && (
isPrivate
- || isLocal
- || owner.isClass && owner.isEffectivelyFinal
- )
+ || isLocalToBlock
+ )
)
+ /** Is this symbol effectively final or a concrete term member of sealed class whose childred do not override it */
+ final def isEffectivelyFinalOrNotOverridden: Boolean = isEffectivelyFinal || (isTerm && !isDeferred && isNotOverridden)
+
+ /** Is this symbol owned by a package? */
+ final def isTopLevel = owner.isPackageClass
- /** Is this symbol locally defined? I.e. not accessed from outside `this` instance */
+ /** Is this symbol defined in a block? */
+ @deprecated("Use isLocalToBlock instead", "2.11.0")
final def isLocal: Boolean = owner.isTerm
+ /** Is this symbol defined in a block? */
+ final def isLocalToBlock: 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)? */
+ /** Is this class nested in another class or module (not a package). Includes locally defined classes. */
def isNestedClass = false
/** Is this class locally defined?
@@ -845,41 +972,36 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
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
+ (isClass || isType || isModule) && info.dealiasWiden/*.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?
+ def isOnlyRefinementMember = (
+ isTerm // Type members are unaffected
+ && owner.isRefinementClass // owner must be a refinement class
+ && isPossibleInRefinement // any overridden symbols must also have refinement class owners
+ && !isConstant // Must not be a constant. Question: Can we exclude @inline methods as well?
+ && isDeclaredByOwner // Must be explicitly declared in the refinement (not synthesized from glb)
+ )
+ // "(owner.info decl name) == this" is inadequate, because "name" might
+ // be overloaded in owner - and this might be an overloaded symbol.
+ // TODO - make this cheaper and see where else we should be doing something similar.
+ private def isDeclaredByOwner = (owner.info decl name).alternatives exists (alternatives contains _)
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
+ final def isPossibleInRefinement = (
+ !isConstructor
+ && allOverriddenSymbols.forall(_.owner.isRefinementClass) // this includes allOverriddenSymbols.isEmpty
+ )
/** 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 ||
@@ -888,13 +1010,43 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
supersym == NoSymbol || supersym.isIncompleteIn(base)
}
- // Does not always work if the rawInfo is a SourcefileLoader, see comment
- // in "def coreClassesFirst" in Global.
- def exists = !owner.isPackageClass || { rawInfo.load(this); rawInfo != NoType }
+ def exists: Boolean = !isTopLevel || {
+ val isSourceLoader = rawInfo match {
+ case sl: SymLoader => sl.fromSource
+ case _ => false
+ }
+ def warnIfSourceLoader() {
+ if (isSourceLoader)
+ // Predef is completed early due to its autoimport; we used to get here when type checking its
+ // parent LowPriorityImplicits. See comment in c5441dc for more elaboration.
+ // Since the fix for SI-7335 Predef parents must be defined in Predef.scala, and we should not
+ // get here anymore.
+ devWarning(s"calling Symbol#exists with sourcefile based symbol loader may give incorrect results.");
+ }
+
+ rawInfo load this
+ rawInfo != NoType || { warnIfSourceLoader(); false }
+ }
final def isInitialized: Boolean =
validTo != NoPeriod
+ /** We consider a symbol to be thread-safe, when multiple concurrent threads can call its methods
+ * (either directly or indirectly via public reflection or internal compiler infrastructure),
+ * without any locking and everything works as it should work.
+ *
+ * In its basic form, `isThreadsafe` always returns false. Runtime reflection augments reflection infrastructure
+ * with threadsafety-tracking mechanism implemented in `SynchronizedSymbol` that communicates with underlying completers
+ * and can sometimes return true if the symbol has been completed to the point of thread safety.
+ *
+ * The `purpose` parameter signifies whether we want to just check immutability of certain flags for the given mask.
+ * This is necessary to enable robust auto-initialization of `Symbol.flags` for runtime reflection, and is also quite handy
+ * in avoiding unnecessary initializations when requesting for flags that have already been set.
+ */
+ def isThreadsafe(purpose: SymbolOps): Boolean = false
+ def markFlagsCompleted(mask: Long): this.type = this
+ def markAllCompleted(): this.type = this
+
/** Can this symbol be loaded by a reflective mirror?
*
* Scalac relies on `ScalaSignature' annotation to retain symbols across compilation runs.
@@ -916,14 +1068,14 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
if (isAliasType) return true
if (isType && isNonClassType) return false
if (isRefinementClass) return false
- return true
+ true
}
- /** The variance of this symbol as an integer */
- final def variance: Int =
- if (isCovariant) 1
- else if (isContravariant) -1
- else 0
+ /** The variance of this symbol. */
+ def variance: Variance =
+ if (isCovariant) Covariant
+ else if (isContravariant) Contravariant
+ else Invariant
/** The sequence number of this parameter symbol among all type
* and value parameters of symbol's owner. -1 if symbol does not
@@ -947,23 +1099,27 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// ------ owner attribute --------------------------------------------------------------
+ /** In general when seeking the owner of a symbol, one should call `owner`.
+ * The other possibilities include:
+ * - call `safeOwner` if it is expected that the target may be NoSymbol
+ * - call `assertOwner` if it is an unrecoverable error if the target is NoSymbol
+ *
+ * `owner` behaves like `safeOwner`, but logs NoSymbol.owner calls under -Xdev.
+ * `assertOwner` aborts compilation immediately if called on NoSymbol.
+ */
def owner: Symbol = {
if (Statistics.hotEnabled) Statistics.incCounter(ownerCount)
rawowner
}
+ final def safeOwner: Symbol = if (this eq NoSymbol) NoSymbol else owner
+ final def assertOwner: Symbol = if (this eq NoSymbol) abort("no-symbol does not have an owner") else owner
// 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
- }
+ saveOriginalOwner(this)
assert(isCompilerUniverse, "owner_= is not thread-safe; cannot be run in reflexive code")
if (traceSymbolActivity)
traceSymbols.recordNewSymbolOwner(this, owner)
@@ -993,10 +1149,12 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// ------ name attribute --------------------------------------------------------------
- /** If this symbol has an expanded name, its original name, otherwise its name itself.
- * @see expandName
+ @deprecated("Use unexpandedName", "2.11.0") def originalName: Name = unexpandedName
+
+ /** If this symbol has an expanded name, its original (unexpanded) name,
+ * otherwise the name itself.
*/
- def originalName: Name = nme.originalName(nme.dropLocalSuffix(name))
+ def unexpandedName: Name = nme.unexpandedName(name)
/** The name of the symbol before decoding, e.g. `\$eq\$eq` instead of `==`.
*/
@@ -1004,7 +1162,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** The decoded name of the symbol, e.g. `==` instead of `\$eq\$eq`.
*/
- def decodedName: String = nme.dropLocalSuffix(name).decode
+ def decodedName: String = name.decode
private def addModuleSuffix(n: Name): Name =
if (needsModuleSuffix) n append nme.MODULE_SUFFIX_STRING else n
@@ -1023,7 +1181,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
)
/** These should be moved somewhere like JavaPlatform.
*/
- def javaSimpleName: Name = addModuleSuffix(nme.dropLocalSuffix(simpleName))
+ def javaSimpleName: Name = addModuleSuffix(simpleName.dropLocal)
def javaBinaryName: Name = addModuleSuffix(fullNameInternal('/'))
def javaClassName: String = addModuleSuffix(fullNameInternal('.')).toString
@@ -1041,10 +1199,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
private def fullNameInternal(separator: Char): Name = (
if (isRoot || isRootPackage || this == NoSymbol) name
else if (owner.isEffectiveRoot) name
- else ((effectiveOwner.enclClass.fullNameAsName(separator) append separator): Name) append name
+ else effectiveOwner.enclClass.fullNameAsName(separator) append (separator, name)
)
- def fullNameAsName(separator: Char): Name = nme.dropLocalSuffix(fullNameInternal(separator))
+ def fullNameAsName(separator: Char): Name = fullNameInternal(separator).dropLocal
/** The encoded full path name of this symbol, where outer names and inner names
* are separated by periods.
@@ -1082,9 +1240,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
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
@@ -1101,12 +1256,13 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
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)
+ // Package before Module, Module before Method, or we might grab the wrong guy.
+ if ((newFlags & PACKAGE) != 0)
createPackageSymbol(name, pos, newFlags | PackageFlags)
else if ((newFlags & MODULE) != 0)
createModuleSymbol(name, pos, newFlags)
+ else if ((newFlags & METHOD) != 0)
+ createMethodSymbol(name, pos, newFlags)
else if ((newFlags & PARAM) != 0)
createValueParameterSymbol(name, pos, newFlags)
else
@@ -1144,7 +1300,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* as public.
*/
def accessBoundary(base: Symbol): Symbol = {
- if (hasFlag(PRIVATE) || isLocal) owner
+ if (hasFlag(PRIVATE) || isLocalToBlock) owner
else if (hasAllFlags(PROTECTED | STATIC | JAVA)) enclosingRootClass
else if (hasAccessBoundary && !phase.erasedTypes) privateWithin
else if (hasFlag(PROTECTED)) base
@@ -1166,7 +1322,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
private[this] var _privateWithin: Symbol = _
def privateWithin = {
- if (!isCompilerUniverse && needsInitialize(isFlagRelated = false, mask = 0)) initialize
+ // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method.
+ if (!isCompilerUniverse && !isThreadsafe(purpose = AllOps)) initialize
_privateWithin
}
def privateWithin_=(sym: Symbol) { _privateWithin = sym }
@@ -1187,20 +1344,61 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
}
- /** 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.
+ /** The "type" of this symbol. The type of a term symbol is its usual
+ * type. A TypeSymbol is more complicated; see that class for elaboration.
+ * Since tpe forwards to tpe_*, if you call it on a type symbol with unapplied
+ * type parameters, the type returned will contain dummies types. These will
+ * hide legitimate errors or create spurious ones if used as normal types.
*
* For type symbols, `tpe` is different than `info`. `tpe` returns a typeRef
* to the type symbol, `info` returns the type information of the type symbol,
* e.g. a ClassInfoType for classes or a TypeBounds for abstract types.
*/
- def tpe: Type = info
- def tpeHK: Type = tpe
+ final def tpe: Type = tpe_*
+
+ /** typeConstructor throws an exception when called on term
+ * symbols; this is a more forgiving alternative. Calls
+ * typeConstructor on TypeSymbols, returns info otherwise.
+ */
+ def tpeHK: Type = info
+
+ /** Only applicable to TypeSymbols, it is the type corresponding
+ * to the symbol itself. For instance, the type of a List might
+ * be List[Int] - the same symbol's typeConstructor is simply List.
+ * One might be tempted to write that as List[_], and in some
+ * contexts this is possible, but it is discouraged because it is
+ * syntactically indistinguishable from and easily confused with the
+ * type List[T] forSome { type T; }, which can also be written List[_].
+ */
+ def typeConstructor: Type = (
+ // Avoiding a third override in NoSymbol to preserve bimorphism
+ if (this eq NoSymbol)
+ abort("no-symbol does not have a type constructor (this may indicate scalac cannot find fundamental classes)")
+ else
+ abort("typeConstructor inapplicable for " + this)
+ )
+
+ /** The type of this symbol, guaranteed to be of kind *.
+ * If there are unapplied type parameters, they will be
+ * substituted with dummy type arguments derived from the
+ * type parameters. Such types are not valid in a general
+ * sense and will cause difficult-to-find bugs if allowed
+ * to roam free.
+ *
+ * If you call tpe_* explicitly to obtain these types,
+ * you are responsible for them as if it they were your own
+ * minor children.
+ */
+ def tpe_* : Type = info
+
+ // Alternate implementation of def tpe for warning about misuse,
+ // disabled to keep the method maximally hotspot-friendly:
+ // def tpe: Type = {
+ // val result = tpe_*
+ // if (settings.debug.value && result.typeArgs.nonEmpty)
+ // printCaller(s"""Call to ${this.tpe} created $result: call tpe_* or tpeHK""")("")
+ // result
+ // }
/** Get type info associated with symbol at current phase, after
* ensuring that symbol is initialized (i.e. type is completed).
@@ -1236,13 +1434,13 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
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)
+ if (cnt == 3) abort(s"no progress in completing $this: $tp")
}
rawInfo
}
catch {
case ex: CyclicReference =>
- debugwarn("... hit cycle trying to complete " + this.fullLocationString)
+ devWarning("... hit cycle trying to complete " + this.fullLocationString)
throw ex
}
@@ -1254,9 +1452,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
/** Set initial info. */
- def setInfo(info: Type): this.type = { info_=(info); this }
+ 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))
+ 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
@@ -1342,6 +1540,13 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
assert(isCompilerUniverse)
if (infos == null || runId(infos.validFrom) == currentRunId) {
infos
+ } else if (isPackageClass) {
+ // SI-7801 early phase package scopes are mutated in new runs (Namers#enterPackage), so we have to
+ // discard transformed infos, rather than just marking them as from this run.
+ val oldest = infos.oldest
+ oldest.validFrom = validTo
+ this.infos = oldest
+ oldest
} else {
val prev1 = adaptInfos(infos.prev)
if (prev1 ne infos.prev) prev1
@@ -1351,10 +1556,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
_validTo = period(currentRunId, pid)
phase = phaseWithId(pid)
- val info1 = (
- if (isPackageClass) infos.info
- else adaptToNewRunMap(infos.info)
- )
+ val info1 = adaptToNewRunMap(infos.info)
if (info1 eq infos.info) {
infos.validFrom = validTo
infos
@@ -1374,53 +1576,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
if (!isInitialized) info
this
}
-
- /** Called when the programmer requests information that might require initialization of the underlying symbol.
- *
- * `isFlagRelated` and `mask` describe the nature of this information.
- * isFlagRelated = true means that the programmer needs particular bits in flags.
- * isFlagRelated = false means that the request is unrelated to flags (annotations or privateWithin).
- *
- * In our current architecture, symbols for top-level classes and modules
- * are created as dummies. Package symbols just call newClass(name) or newModule(name) and
- * consider their job done.
- *
- * In order for such a dummy to provide meaningful info (e.g. a list of its members),
- * it needs to go through unpickling. Unpickling is a process of reading Scala metadata
- * from ScalaSignature annotations and assigning it to symbols and types.
- *
- * A single unpickling session takes a top-level class or module, parses the ScalaSignature annotation
- * and then reads metadata for the unpicklee, its companion (if any) and all their members recursively
- * (i.e. the pickle not only contains info about directly nested classes/modules, but also about
- * classes/modules nested into those and so on).
- *
- * Unpickling is triggered automatically whenever typeSignature (info in compiler parlance) is called.
- * This happens because package symbols assign completer thunks to the dummies they create.
- * Therefore metadata loading happens lazily and transparently.
- *
- * Almost transparently. Unfortunately metadata isn't limited to just signatures (i.e. lists of members).
- * It also includes flags (which determine e.g. whether a class is sealed or not), annotations and privateWithin.
- * This gives rise to unpleasant effects like in SI-6277, when a flag test called on an uninitialize symbol
- * produces incorrect results.
- *
- * One might think that the solution is simple: automatically call the completer whenever one needs
- * flags, annotations and privateWithin - just like it's done for typeSignature. Unfortunately, this
- * leads to weird crashes in scalac, and currently we can't attempt to fix the core of the compiler
- * risk stability a few weeks before the final release.
- *
- * However we do need to fix this for runtime reflection, since it's not something we'd like to
- * expose to reflection users. Therefore a proposed solution is to check whether we're in a
- * runtime reflection universe and if yes then to commence initialization.
- */
- protected def needsInitialize(isFlagRelated: Boolean, mask: Long) =
- !isInitialized && (flags & LOCKED) == 0 && shouldTriggerCompleter(this, if (infos ne null) infos.info else null, isFlagRelated, mask)
-
- /** 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
+ def maybeInitialize = {
+ try { initialize ; true }
+ catch { case _: CyclicReference => debuglog("Hit cycle in maybeInitialize of $this") ; false }
}
/** Was symbol's type updated during given phase? */
@@ -1436,21 +1594,20 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* 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()
- }
+ def cookJavaRawInfo(): this.type = {
+ // only try once...
+ if (phase.erasedTypes || (this hasFlag TRIEDCOOKING))
+ return this
- protected def doCookJavaRawInfo(): Unit
+ this setFlag TRIEDCOOKING
+ info // force the current info
+ if (isJavaDefined || isType && owner.isJavaDefined)
+ this modifyInfo rawToExistential
+ else if (isOverloaded)
+ alternatives withFilter (_.isJavaDefined) foreach (_ modifyInfo rawToExistential)
- /** 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)
+ this
+ }
/** The logic approximately boils down to finding the most recent phase
* which immediately follows any of parser, namer, typer, or erasure.
@@ -1472,23 +1629,27 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* assumption: if a type starts out as monomorphic, it will not acquire
* type parameters later.
*/
+ // NOTE: overridden in SynchronizedSymbols with the code copy/pasted
+ // don't forget to modify the code over there if you modify this method
def unsafeTypeParams: List[Symbol] =
if (isMonomorphicType) Nil
- else atPhase(unsafeTypeParamPhase)(rawInfo.typeParams)
+ else enteringPhase(unsafeTypeParamPhase)(rawInfo.typeParams)
/** The type parameters of this symbol.
* assumption: if a type starts out as monomorphic, it will not acquire
* type parameters later.
*/
+ // NOTE: overridden in SynchronizedSymbols with the code copy/pasted
+ // don't forget to modify the code over there if you modify this method
def typeParams: List[Symbol] =
if (isMonomorphicType) Nil
else {
// 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)
+ enteringPhase(phaseOf(infos.validFrom))(rawInfo load this)
if (validTo == NoPeriod)
- atPhase(phaseOf(infos.validFrom))(rawInfo load this)
+ enteringPhase(phaseOf(infos.validFrom))(rawInfo load this)
rawInfo.typeParams
}
@@ -1555,7 +1716,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def makeSerializable() {
info match {
case ci @ ClassInfoType(_, _, _) =>
- setInfo(ci.copy(parents = ci.parents :+ SerializableClass.tpe))
+ setInfo(ci.copy(parents = ci.parents :+ SerializableTpe))
case i =>
abort("Only ClassInfoTypes can be made serializable: "+ i)
}
@@ -1578,7 +1739,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* the annotations attached to member a definition (class, method, type, field).
*/
def annotations: List[AnnotationInfo] = {
- if (!isCompilerUniverse && needsInitialize(isFlagRelated = false, mask = 0)) initialize
+ // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method.
+ if (!isCompilerUniverse && !isThreadsafe(purpose = AllOps)) initialize
_annotations
}
@@ -1645,6 +1807,19 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* and is this class symbol also different from Null or Nothing? */
def isNonBottomSubClass(that: Symbol): Boolean = false
+ /** Is this class symbol Null or Nothing,
+ * and (if Null) is `that` inhabited by null?
+ * If this is Nothing, of course, it is a
+ * subclass of `that` by definition.
+ *
+ * TODO - what is implied by the fact that AnyVal now has
+ * infinitely many non-bottom subclasses, not only 9?
+ */
+ def isBottomSubClass(that: Symbol) = (
+ (this eq NothingClass)
+ || (this eq NullClass) && that.isClass && (that ne NothingClass) && !(that isNonBottomSubClass AnyValClass)
+ )
+
/** Overridden in NullClass and NothingClass for custom behavior.
*/
def isSubClass(that: Symbol) = isNonBottomSubClass(that)
@@ -1663,12 +1838,23 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def filter(cond: Symbol => Boolean): Symbol =
if (isOverloaded) {
- val alts = alternatives
- val alts1 = alts filter cond
- if (alts1 eq alts) this
+ var changed = false
+ var alts0: List[Symbol] = alternatives
+ var alts1: List[Symbol] = Nil
+
+ while (alts0.nonEmpty) {
+ if (cond(alts0.head))
+ alts1 ::= alts0.head
+ else
+ changed = true
+
+ alts0 = alts0.tail
+ }
+
+ if (!changed) this
else if (alts1.isEmpty) NoSymbol
else if (alts1.tail.isEmpty) alts1.head
- else owner.newOverloaded(info.prefix, alts1)
+ else owner.newOverloaded(info.prefix, alts1.reverse)
}
else if (cond(this)) this
else NoSymbol
@@ -1679,10 +1865,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
result
}
- @inline final def map(f: Symbol => Symbol): Symbol = if (this eq NoSymbol) this else f(this)
-
- final def toOption: Option[Symbol] = if (exists) Some(this) else None
-
// ------ cloneing -------------------------------------------------------------------
/** A clone of this symbol. */
@@ -1748,11 +1930,13 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
def thisSym: Symbol = this
+ def hasSelfType = thisSym.tpeHK != this.tpeHK
+
/** The type of `this` in a class, or else the type of the symbol itself. */
- def typeOfThis = thisSym.tpe
+ def typeOfThis = thisSym.tpe_*
- /** If symbol is a class, the type <code>this.type</code> in this class,
- * otherwise <code>NoPrefix</code>.
+ /** If symbol is a class, the type `this.type` in this class,
+ * otherwise `NoPrefix`.
* We always have: thisType <:< typeOfThis
*/
def thisType: Type = NoPrefix
@@ -1773,7 +1957,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
//
// The slightly more principled approach of using the paramss of the
// primary constructor leads to cycles in, for example, pos/t5084.scala.
- val primaryNames = constrParamAccessors.map(acc => nme.dropLocalSuffix(acc.name))
+ val primaryNames = constrParamAccessors map (_.name.dropLocal)
caseFieldAccessorsUnsorted.sortBy { acc =>
primaryNames indexWhere { orig =>
(acc.name == orig) || (acc.name startsWith (orig append "$"))
@@ -1792,7 +1976,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** 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)
+ ownerTp decl localName
}
/** The module corresponding to this module class (note that this
@@ -1886,15 +2070,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* 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
- }
- }
+ def originalEnclosingMethod: Symbol = Symbols.this.originalEnclosingMethod(this)
/** The method or class which logically encloses the current symbol.
* If the symbol is defined in the initialization part of a template
@@ -1920,18 +2096,15 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* (or, for traits: `$init`) of `C`.
*
*/
- def logicallyEnclosingMember: Symbol =
+ final def logicallyEnclosingMember: Symbol =
if (isLocalDummy) enclClass.primaryConstructor
- else if (isMethod || isClass) this
+ else if (isMethod || isClass || this == NoSymbol) this
+ else if (this == NoSymbol) { devWarningDumpStack("NoSymbol.logicallyEnclosingMember", 15); 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 (isTopLevel) {
if (isClass) this else moduleClass
} else owner.enclosingTopLevelClass
@@ -1940,11 +2113,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
!rawInfoIsNoType
&& (this.effectiveOwner == that.effectiveOwner)
&& ( !this.effectiveOwner.isPackageClass
- || (this.sourceFile eq null)
- || (that.sourceFile eq null)
- || (this.sourceFile.path == that.sourceFile.path) // Cheap possibly wrong check, then expensive normalization
- || (this.sourceFile.canonicalPath == that.sourceFile.canonicalPath)
- )
+ || (this.associatedFile eq NoAbstractFile)
+ || (that.associatedFile eq NoAbstractFile)
+ || (this.associatedFile.path == that.associatedFile.path) // Cheap possibly wrong check, then expensive normalization
+ || (this.associatedFile.canonicalPath == that.associatedFile.canonicalPath)
+ )
)
/** The internal representation of classes and objects:
@@ -2040,70 +2213,113 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* @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 = {
- //OPT cut down on #closures by special casing non-overloaded case
- // was: ofclazz.info.nonPrivateDecl(name) filter (sym =>
- // !sym.isTerm || (site.memberType(this) matches site.memberType(sym)))
- val result = ofclazz.info.nonPrivateDecl(name)
- def qualifies(sym: Symbol) = !sym.isTerm || (site.memberType(this) matches site.memberType(sym))
- if ((result eq NoSymbol) || !result.isOverloaded && qualifies(result)) result
- else result filter qualifies
- }
+ final def matchingSymbol(ofclazz: Symbol, site: Type): Symbol =
+ matchingSymbolInternal(site, ofclazz.info nonPrivateDecl name)
/** 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)))
+ matchingSymbolInternal(site, site.nonPrivateMemberAdmitting(name, admit))
- /** The symbol, in class `ofclazz`, that is overridden by this symbol.
+ private def matchingSymbolInternal(site: Type, candidate: Symbol): Symbol = {
+ def qualifies(sym: Symbol) = !sym.isTerm || ((site memberType this) matches (site memberType sym))
+ //OPT cut down on #closures by special casing non-overloaded case
+ if (candidate.isOverloaded) candidate filter qualifies
+ else if (qualifies(candidate)) candidate
+ else NoSymbol
+ }
+
+ /** The symbol, in class `baseClass`, that is overridden by this symbol.
*
- * @param ofclazz is a base class of this symbol's owner.
+ * @param baseClass is a base class of this symbol's owner.
*/
- final def overriddenSymbol(ofclazz: Symbol): Symbol =
- if (isClassConstructor) NoSymbol else matchingSymbol(ofclazz, owner.thisType)
+ final def overriddenSymbol(baseClass: Symbol): Symbol = (
+ // concrete always overrides abstract, so don't let an abstract definition
+ // claim to be overriding an inherited concrete one.
+ matchingInheritedSymbolIn(baseClass) filter (res => res.isDeferred || !this.isDeferred)
+ )
+
+ private def matchingInheritedSymbolIn(baseClass: Symbol): Symbol =
+ if (canMatchInheritedSymbols) matchingSymbol(baseClass, owner.thisType) else NoSymbol
/** 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)
+ final def overridingSymbol(ofclazz: Symbol): Symbol = (
+ if (canMatchInheritedSymbols)
+ matchingSymbol(ofclazz, ofclazz.thisType)
+ else
+ NoSymbol
+ )
+
+ /** If false, this symbol cannot possibly participate in an override,
+ * either as overrider or overridee. For internal use; you should consult
+ * with isOverridingSymbol. This is used by isOverridingSymbol to escape
+ * the recursive knot.
+ */
+ private def canMatchInheritedSymbols = (
+ owner.isClass
+ && !this.isClass
+ && !this.isConstructor
+ )
- /** Returns all symbols overriden by this symbol. */
- final def allOverriddenSymbols: List[Symbol] =
- if (!owner.isClass) Nil
- else owner.ancestors map overriddenSymbol filter (_ != NoSymbol)
+ // All the symbols overridden by this symbol and this symbol at the head,
+ // or Nil if this is NoSymbol.
+ def overrideChain = (
+ if (this eq NoSymbol) Nil
+ else if (isOverridingSymbol) this :: allOverriddenSymbols
+ else this :: Nil
+ )
+
+ /** Returns all symbols overridden by this symbol. */
+ final def allOverriddenSymbols: List[Symbol] = {
+ def loop(xs: List[Symbol]): List[Symbol] = xs match {
+ case Nil => Nil
+ case x :: xs =>
+ overriddenSymbol(x) match {
+ case NoSymbol => loop(xs)
+ case sym => sym :: loop(xs)
+ }
+ }
+ if (isOverridingSymbol) loop(owner.ancestors) else Nil
+ }
/** 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)
+ lazy val isOverridingSymbol = (
+ canMatchInheritedSymbols
+ && owner.ancestors.exists(base => overriddenSymbol(base) != 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
+ @tailrec def loop(bases: List[Symbol]): Symbol = bases match {
+ case Nil => NoSymbol
+ case base :: rest =>
+ val sym = overriddenSymbol(base)
+ if (sym == NoSymbol) loop(rest) else sym
}
- NoSymbol
+ if (isOverridingSymbol) loop(owner.ancestors) else 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)
+ final def extendedOverriddenSymbols: List[Symbol] = (
+ if (canMatchInheritedSymbols)
+ owner.thisSym.ancestors map overriddenSymbol filter (_ != NoSymbol)
+ else
+ Nil
+ )
/** 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
+ @deprecated("Use `superSymbolIn` instead", "2.11.0")
+ final def superSymbol(base: Symbol): Symbol = superSymbolIn(base)
+
+ final def superSymbolIn(base: Symbol): Symbol = {
+ var bcs = base.info.baseClasses dropWhile (owner != _) drop 1
var sym: Symbol = NoSymbol
while (!bcs.isEmpty && sym == NoSymbol) {
if (!bcs.head.isImplClass)
@@ -2116,22 +2332,30 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** 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)
+ @deprecated("Use `getterIn` instead", "2.11.0")
+ final def getter(base: Symbol): Symbol = getterIn(base)
- def getterName: TermName = (
- if (isSetter) nme.setterToGetter(name.toTermName)
- else if (nme.isLocalName(name)) nme.localToGetter(name.toTermName)
- else name.toTermName
- )
+ final def getterIn(base: Symbol): Symbol =
+ base.info decl getterName filter (_.hasAccessorFlag)
+
+ def getterName: TermName = name.getterName
+ def setterName: TermName = name.setterName
+ def localName: TermName = name.localName
/** The setter of this value or getter definition, or NoSymbol if none exists */
- final def setter(base: Symbol): Symbol = setter(base, false)
+ @deprecated("Use `setterIn` instead", "2.11.0")
+ final def setter(base: Symbol, hasExpandedName: Boolean = needsExpandedSetterName): Symbol =
+ setterIn(base, hasExpandedName)
- 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)
- }
+ final def setterIn(base: Symbol, hasExpandedName: Boolean = needsExpandedSetterName): Symbol =
+ base.info decl setterNameInBase(base, hasExpandedName) filter (_.hasAccessorFlag)
+
+ def needsExpandedSetterName = (
+ if (isMethod) hasStableFlag && !isLazy
+ else hasNoFlags(LAZY | MUTABLE)
+ )
+ def setterNameInBase(base: Symbol, expanded: Boolean): TermName =
+ if (expanded) nme.expandedSetterName(setterName, base) else setterName
/** If this is a derived value class, return its unbox method
* or NoSymbol if it does not exist.
@@ -2188,35 +2412,20 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
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.
+ final def sourceFile: AbstractFile =
+ if ((associatedFile eq NoAbstractFile) || (associatedFile.path endsWith ".class")) null else associatedFile
- /** 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.
+ /** Overridden in ModuleSymbols to delegate to the module class.
+ * Never null; if there is no associated file, returns NoAbstractFile.
*/
- private def sourceFileOnly(file: AbstractFile): AbstractFile =
- if ((file eq null) || (file.path endsWith ".class")) null else file
-
- private def binaryFileOnly(file: AbstractFile): AbstractFile =
- if ((file eq null) || !(file.path endsWith ".class")) null else file
-
- final def binaryFile: AbstractFile = binaryFileOnly(associatedFile)
- final def sourceFile: AbstractFile = sourceFileOnly(associatedFile)
-
- /** Overridden in ModuleSymbols to delegate to the module class. */
def associatedFile: AbstractFile = enclosingTopLevelClass.associatedFile
def associatedFile_=(f: AbstractFile) { abort("associatedFile_= inapplicable for " + this) }
- @deprecated("Use associatedFile_= instead", "2.10.0")
- def sourceFile_=(f: AbstractFile): Unit = associatedFile_=(f)
-
/** If this is a sealed class, its known direct subclasses.
* Otherwise, the empty set.
*/
@@ -2228,11 +2437,13 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
@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 }
+ @inline final def fold[T](none: => T)(f: Symbol => T): T = if (this ne NoSymbol) f(this) else none
+ @inline final def map(f: Symbol => Symbol): Symbol = if (this eq NoSymbol) this else f(this)
-// ------ toString -------------------------------------------------------------------
+ final def toOption: Option[Symbol] = if (exists) Some(this) else None
- /** A tag which (in the ideal case) uniquely identifies class symbols */
- final def tag: Int = fullName.##
+
+// ------ toString -------------------------------------------------------------------
/** The simple name of this Symbol */
final def simpleName: Name = name
@@ -2251,20 +2462,19 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
else if (isClass) "class"
else if (isType && !isParameter) "type"
else if (isVariable) "var"
- else if (isPackage) "package"
+ else if (hasPackageFlag) "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")
+ if (isTermMacro) ("term macro", "macro method", "MACM")
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 (isPackage) ("package", "package", "PK")
else if (isPackageObject) ("package object", "package", "PKO")
else if (isPackageObjectClass) ("package object class", "package", "PKOC")
else if (isAnonymousClass) ("anonymous class", "anonymous class", "AC")
@@ -2279,7 +2489,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
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 && (owner.hasCompleteInfo && isPrimaryConstructor)) ("primary constructor", "constructor", "PCTOR")
else if (isClassConstructor) ("constructor", "constructor", "CTOR")
else if (isSourceMethod) ("method", "method", "METH")
else if (isTerm) ("value", "value", "VAL")
@@ -2321,14 +2531,15 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* If !settings.debug translates expansions of operators back to operator symbol.
* E.g. $eq => =.
* If settings.uniqid, adds id.
+ * If settings.Yshowsymowners, adds owner's id
* If settings.Yshowsymkinds, adds abbreviated symbol kind.
*/
- def nameString: String = (
- if (!settings.uniqid.value && !settings.Yshowsymkinds.value) "" + originalName.decode
- else if (settings.uniqid.value && !settings.Yshowsymkinds.value) originalName.decode + "#" + id
- else if (!settings.uniqid.value && settings.Yshowsymkinds.value) originalName.decode + "#" + abbreviatedKindString
- else originalName.decode + "#" + id + "#" + abbreviatedKindString
- )
+ def nameString: String = {
+ val name_s = if (settings.debug.value) "" + unexpandedName else unexpandedName.dropLocal.decode
+ val kind_s = if (settings.Yshowsymkinds.value) "#" + abbreviatedKindString else ""
+
+ name_s + idString + kind_s
+ }
def fullNameString: String = {
def recur(sym: Symbol): String = {
@@ -2341,15 +2552,23 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
/** If settings.uniqid is set, the symbol's id, else "" */
- final def idString = if (settings.uniqid.value) "#"+id else ""
+ final def idString = {
+ val id_s = if (settings.uniqid.value) "#"+id else ""
+ val owner_s = if (settings.Yshowsymowners.value) "@"+owner.id else ""
+ id_s + owner_s
+ }
/** 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
- )
+ override def toString: String = {
+ if (isPackageObjectOrClass && !settings.debug)
+ s"package object ${owner.decodedName}"
+ else compose(
+ kindString,
+ if (hasMeaninglessName) owner.decodedName + idString else nameString
+ )
+ }
/** String representation of location.
*/
@@ -2374,6 +2593,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
if (settings.debug.value) parentsString(tp.parents)
else briefParentsString(tp.parents)
)
+ def isStructuralThisType = (
+ // prevents disasters like SI-8158
+ owner.isInitialized && owner.isStructuralRefinement && tp == owner.tpe
+ )
if (isType) typeParamsString(tp) + (
if (isClass) " extends " + parents
else if (isAliasType) " = " + tp.resultType
@@ -2384,15 +2607,23 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
)
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
+ case PolyType(tparams, res) => typeParamsString(tp) + infoString(res)
+ case NullaryMethodType(res) => infoString(res)
+ case MethodType(params, res) => valueParamsString(tp) + infoString(res)
+ case _ if isStructuralThisType => ": " + owner.name
+ case _ => ": " + tp
}
}
def infosString = infos.toString
- def debugLocationString = fullLocationString + " (flags: " + debugFlagString + ")"
+ def debugLocationString = {
+ val pre = flagString match {
+ case "" => ""
+ case s if s contains ' ' => "(" + s + ") "
+ case s => s + " "
+ }
+ pre + fullLocationString
+ }
private def defStringCompose(infoString: String) = compose(
flagString,
@@ -2458,31 +2689,32 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
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
+ /*** !!! TODO: shouldn't we do something like the following:
+ override def isOverloaded = (
+ if (this.isInitialized)
+ this hasFlag OVERLOADED
+ else
+ (infos ne null) && infos.info.isInstanceOf[OverloadedType]
+ )
+ ***/
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 isDefaultGetter = name containsName nme.DEFAULT_GETTER_STRING
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))
- )
+ override def isPackageObject = isModule && (name == nme.PACKAGE)
// The name in comments is what it is being disambiguated from.
// TODO - rescue CAPTURED from BYNAMEPARAM so we can see all the names.
@@ -2562,36 +2794,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
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])
@@ -2672,17 +2874,36 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
loop(info)
}
+
+ override def exceptions = annotations flatMap ThrownException.unapply
}
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
+ override def variance = if (isLocalToThis) Bivariant else info.typeSymbol.variance
+ override def isContravariant = variance.isContravariant
+ override def isCovariant = variance.isCovariant
final override def isAliasType = true
override def cloneSymbolImpl(owner: Symbol, newFlags: Long): TypeSymbol =
owner.newNonClassSymbol(name, pos, newFlags)
}
+ /** Let's say you have a type definition
+ *
+ * {{{
+ * type T <: Number
+ * }}}
+ *
+ * and tsym is the symbol corresponding to T. Then
+ *
+ * {{{
+ * tsym is an instance of AbstractTypeSymbol
+ * tsym.info == TypeBounds(Nothing, Number)
+ * tsym.tpe == TypeRef(NoPrefix, T, List())
+ * }}}
+ */
class AbstractTypeSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName)
extends TypeSymbol(initOwner, initPos, initName) {
type TypeOfClonedSymbol = TypeSymbol
@@ -2711,7 +2932,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
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
@@ -2729,7 +2949,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
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
@@ -2751,63 +2970,63 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
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
- * }}}
+ /** A polymorphic type symbol has two distinct "types":
*
- * and tsym is the symbol corresponding to T. Then
+ * tpe_* a TypeRef with: dummy type args, no unapplied type parameters, and kind *
+ * tpeHK a TypeRef with: no type args, unapplied type parameters, and
+ * kind (*,*,...,*) => * depending on the number of tparams.
*
- * {{{
- * tsym.info = TypeBounds(Nothing, Number)
- * tsym.tpe = TypeRef(NoPrefix, T, List())
- * }}}
- */
- override def tpe: Type = {
- if (tpeCache eq NoType) throw CyclicReference(this, typeConstructor)
+ * The dummy type args in tpe_* are created by wrapping a TypeRef
+ * around the type parameter symbols. Types containing dummies will
+ * hide errors or introduce spurious ones if they are passed around
+ * as if normal types. They should only be used in local operations
+ * where they will either be discarded immediately after, or will
+ * undergo substitution in which the dummies are replaced by actual
+ * type arguments.
+ */
+ override def tpe_* : Type = {
+ maybeUpdateTypeCache()
+ tpeCache
+ }
+ override def typeConstructor: Type = {
+ if (tyconCacheNeedsUpdate)
+ setTyconCache(newTypeRef(Nil))
+ tyconCache
+ }
+ override def tpeHK: Type = typeConstructor
+
+ private def tyconCacheNeedsUpdate = (tyconCache eq null) || tyconRunId != currentRunId
+ private def setTyconCache(tycon: Type) {
+ tyconCache = tycon
+ tyconRunId = currentRunId
+ assert(tyconCache ne null, this)
+ }
+
+ private def maybeUpdateTypeCache() {
if (tpePeriod != currentPeriod) {
- if (isValid(tpePeriod)) {
+ 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)
- }
+ else
+ updateTypeCache() // perform the actual update
}
- assert(tpeCache ne null/*, "" + this + " " + phase*/)//debug
- tpeCache
}
+ private def updateTypeCache() {
+ if (tpeCache eq NoType)
+ throw CyclicReference(this, typeConstructor)
- /** @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
+ if (isInitialized)
+ tpePeriod = currentPeriod
- override def typeConstructor: Type = {
- if ((tyconCache eq null) || tyconRunId != currentRunId) {
- tyconCache = newTypeRef(Nil)
- tyconRunId = currentRunId
- }
- assert(tyconCache ne null)
- tyconCache
+ tpeCache = NoType // cycle marker
+ val noTypeParams = phase.erasedTypes && this != ArrayClass || unsafeTypeParams.isEmpty
+ tpeCache = newTypeRef(
+ if (noTypeParams) Nil
+ else unsafeTypeParams map (_.typeConstructor)
+ )
+ // Avoid carrying around different types in tyconCache and tpeCache
+ // for monomorphic types.
+ if (noTypeParams && tyconCacheNeedsUpdate)
+ setTyconCache(tpeCache)
}
override def info_=(tp: Type) {
@@ -2833,15 +3052,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* 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)
- }
- }
- }
if (Statistics.hotEnabled) Statistics.incCounter(typeSymbolCount)
}
@@ -2871,11 +3081,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// 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 hasAllFlags GADT_SKOLEM_FLAGS
+ override def isGADTSkolem = this hasAllFlags GADT_SKOLEM_FLAGS.toLong
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 */
@@ -2934,7 +3143,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
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 isNestedClass = !isTopLevel
override def isNumericValueClass = definitions.isNumericValueClass(this)
override def isNumeric = isNumericValueClass
override def isPackageObjectClass = isModuleClass && (name == tpnme.PACKAGE)
@@ -2959,24 +3168,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
override def isLocalClass = (
isAnonOrRefinementClass
- || isLocal
- || !owner.isPackageClass && owner.isLocalClass
+ || isLocalToBlock
+ || !isTopLevel && 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
@@ -2985,8 +3179,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* returned, otherwise, `NoSymbol` is returned.
*/
protected final def companionModule0: Symbol =
- flatOwnerInfo.decl(name.toTermName).suchThat(
- sym => sym.isModule && (sym isCoDefinedWith this) && !sym.isMethod)
+ flatOwnerInfo.decl(name.toTermName).suchThat(sym => sym.isModuleNotMethod && (sym isCoDefinedWith this))
override def companionModule = companionModule0
override def companionSymbol = companionModule0
@@ -3003,7 +3196,13 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
if (c.isOverloaded) c.alternatives.head else c
}
- override def associatedFile = if (owner.isPackageClass) _associatedFile else super.associatedFile
+ override def associatedFile = (
+ if (!isTopLevel) super.associatedFile
+ else {
+ if (_associatedFile eq null) NoAbstractFile // guarantee not null, but save cost of initializing the var
+ else _associatedFile
+ }
+ )
override def associatedFile_=(f: AbstractFile) { _associatedFile = f }
override def reset(completer: Type): this.type = {
@@ -3016,8 +3215,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def thisType: Type = {
val period = thisTypePeriod
if (period != currentPeriod) {
- thisTypePeriod = currentPeriod
if (!isValid(period)) thisTypeCache = ThisType(this)
+ thisTypePeriod = currentPeriod
}
thisTypeCache
}
@@ -3052,9 +3251,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
clone.typeOfThis = typeOfThis
clone.thisSym setName thisSym.name
}
- if (_associatedFile ne null)
- clone.associatedFile = _associatedFile
-
+ clone.associatedFile = _associatedFile
clone
}
@@ -3067,6 +3264,20 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def children = childSet
override def addChild(sym: Symbol) { childSet = childSet + sym }
+ def anonOrRefinementString = {
+ if (hasCompleteInfo) {
+ val label = if (isAnonymousClass) "$anon:" else "refinement of"
+ val parents = parentsString(info.parents map functionNBaseType filterNot (_.typeSymbol == SerializableClass))
+ s"<$label $parents>"
+ }
+ else if (isAnonymousClass) "$anon"
+ else nameString
+ }
+ override def toString = (
+ if (isAnonOrRefinementClass) anonOrRefinementString
+ else super.toString
+ )
+
if (Statistics.hotEnabled) Statistics.incCounter(classSymbolCount)
}
implicit val ClassSymbolTag = ClassTag[ClassSymbol](classOf[ClassSymbol])
@@ -3093,9 +3304,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def typeOfThis = {
val period = typeOfThisPeriod
if (period != currentPeriod) {
- typeOfThisPeriod = currentPeriod
if (!isValid(period))
typeOfThisCache = singleType(owner.thisType, sourceModule)
+ typeOfThisPeriod = currentPeriod
}
typeOfThisCache
}
@@ -3106,9 +3317,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// Skip a package object class, because the members are also in
// the package and we wish to avoid spurious ambiguities as in pos/t3999.
if (!isPackageObjectClass) {
+ implicitMembersCacheValue = tp.implicitMembers
implicitMembersCacheKey1 = tp
implicitMembersCacheKey2 = tp.decls.elems
- implicitMembersCacheValue = tp.implicitMembers
}
}
implicitMembersCacheValue
@@ -3162,6 +3373,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
)
}
trait StubSymbol extends Symbol {
+ devWarning("creating stub symbol to defer error: " + missingMessage)
+
protected def missingMessage: String
/** Fail the stub by throwing a [[scala.reflect.internal.MissingRequirementError]]. */
@@ -3189,8 +3402,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def info = fail(NoType)
override def rawInfo = fail(NoType)
override def companionSymbol = fail(NoSymbol)
-
- debugwarn("creating stub symbol to defer error: " + missingMessage)
}
class StubClassSymbol(owner0: Symbol, name0: TypeName, protected val missingMessage: String) extends ClassSymbol(owner0, owner0.pos, name0) with StubSymbol
class StubTermSymbol(owner0: Symbol, name0: TermName, protected val missingMessage: String) extends TermSymbol(owner0, owner0.pos, name0) with StubSymbol
@@ -3199,11 +3410,16 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def origin: String
}
class FreeTermSymbol(name0: TermName, value0: => Any, val origin: String) extends TermSymbol(NoSymbol, NoPosition, name0) with FreeSymbol with FreeTermSymbolApi {
+ final override def isFreeTerm = true
+ final override def asFreeTerm = this
def value = value0
}
implicit val FreeTermSymbolTag = ClassTag[FreeTermSymbol](classOf[FreeTermSymbol])
- class FreeTypeSymbol(name0: TypeName, val origin: String) extends TypeSkolem(NoSymbol, NoPosition, name0, NoSymbol) with FreeSymbol with FreeTypeSymbolApi
+ class FreeTypeSymbol(name0: TypeName, val origin: String) extends TypeSkolem(NoSymbol, NoPosition, name0, NoSymbol) with FreeSymbol with FreeTypeSymbolApi {
+ final override def isFreeType = true
+ final override def asFreeType = this
+ }
implicit val FreeTypeSymbolTag = ClassTag[FreeTypeSymbol](classOf[FreeTypeSymbol])
/** An object representing a missing symbol */
@@ -3216,10 +3432,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def name = nme.NO_NAME
override def name_=(n: Name) = abort("Cannot set NoSymbol's name to " + n)
- synchronized {
- setInfo(NoType)
- privateWithin = this
- }
+ // Syncnote: no need to synchronize this, because NoSymbol's initialization is triggered by JavaUniverse.init
+ // which is called in universe's constructor - something that's inherently single-threaded
+ setInfo(NoType)
+ privateWithin = this
+
override def info_=(info: Type) = {
infos = TypeHistory(1, NoType, null)
unlock()
@@ -3240,23 +3457,21 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
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 associatedFile = NoAbstractFile
+ override def owner: Symbol = {
+ devWarningDumpStack("NoSymbol.owner", 15)
+ this
+ }
+ override def ownerChain: List[Symbol] = Nil
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
@@ -3272,8 +3487,23 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* @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))
+ val syms1 = mapList(syms)(symFn)
+ mapList(syms1)(_ substInfo (syms, syms1))
+ }
+
+ /** Derives a new list of symbols from the given list by mapping the given
+ * list of `syms` and `as` 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 as arguments to be passed to symFn together with symbols from syms (must be same length)
+ * @param symFn the function to create new symbols
+ * @return the new list of info-adjusted symbols
+ */
+ def deriveSymbols2[A](syms: List[Symbol], as: List[A], symFn: (Symbol, A) => Symbol): List[Symbol] = {
+ val syms1 = map2(syms, as)(symFn)
+ mapList(syms1)(_ substInfo (syms, syms1))
}
/** Derives a new Type by first deriving new symbols as in deriveSymbols,
@@ -3289,6 +3519,22 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
val syms1 = deriveSymbols(syms, symFn)
tpe.substSym(syms, syms1)
}
+
+ /** Derives a new Type by first deriving new symbols as in deriveSymbols2,
+ * then performing the same oldSyms => newSyms substitution on `tpe` as is
+ * performed on the symbol infos in deriveSymbols.
+ *
+ * @param syms the prototypical symbols
+ * @param as arguments to be passed to symFn together with symbols from syms (must be same length)
+ * @param symFn the function to create new symbols based on `as`
+ * @param tpe the prototypical type
+ * @return the new symbol-subsituted type
+ */
+ def deriveType2[A](syms: List[Symbol], as: List[A], symFn: (Symbol, A) => Symbol)(tpe: Type): Type = {
+ val syms1 = deriveSymbols2(syms, as, symFn)
+ tpe.substSym(syms, syms1)
+ }
+
/** Derives a new Type by instantiating the given list of symbols as
* WildcardTypes.
*
@@ -3313,9 +3559,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* @return the newly created, info-adjusted symbols
*/
def cloneSymbolsAndModify(syms: List[Symbol], infoFn: Type => Type): List[Symbol] =
- cloneSymbols(syms) map (_ modifyInfo infoFn)
+ mapList(cloneSymbols(syms))(_ modifyInfo infoFn)
def cloneSymbolsAtOwnerAndModify(syms: List[Symbol], owner: Symbol, infoFn: Type => Type): List[Symbol] =
- cloneSymbolsAtOwner(syms, owner) map (_ modifyInfo infoFn)
+ mapList(cloneSymbolsAtOwner(syms, owner))(_ 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.
@@ -3333,6 +3579,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
def mapParamss[T](sym: Symbol)(f: Symbol => T): List[List[T]] = mmap(sym.info.paramss)(f)
+ def existingSymbols(syms: List[Symbol]): List[Symbol] =
+ syms filter (s => (s ne null) && (s ne NoSymbol))
+
/** Return closest enclosing method, unless shadowed by an enclosing class. */
// TODO Move back to ExplicitOuter when the other call site is removed.
// no use of closures here in the interest of speed.
@@ -3348,25 +3597,26 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
/** A class for type histories */
- private sealed case class TypeHistory(var validFrom: Period, info: Type, prev: TypeHistory) {
+ private 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 + ")"
+ private def phaseString = "%s: %s".format(phaseOf(validFrom), info)
+ override def toString = toList reverseMap (_.phaseString) mkString ", "
def toList: List[TypeHistory] = this :: ( if (prev eq null) Nil else prev.toList )
+
+ def oldest: TypeHistory = if (prev == null) this else prev.oldest
}
// ----- Hoisted closures and convenience methods, for compile time reductions -------
private[scala] final val symbolIsPossibleInRefinement = (sym: Symbol) => sym.isPossibleInRefinement
- private[scala] final val symbolIsNonVariant = (sym: Symbol) => sym.variance == 0
@tailrec private[scala] final
def allSymbolsHaveOwner(syms: List[Symbol], owner: Symbol): Boolean = syms match {
case sym :: rest => sym.owner == owner && allSymbolsHaveOwner(rest, owner)
- case _ => true
+ case _ => true
}
@@ -3374,6 +3624,17 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
Statistics.newView("#symbols")(ids)
+
+// -------------- Completion --------------------------------------------------------
+
+ // is used to differentiate levels of thread-safety in `Symbol.isThreadsafe`
+ case class SymbolOps(isFlagRelated: Boolean, mask: Long)
+ val AllOps = SymbolOps(isFlagRelated = false, mask = 0L)
+ def FlagOps(mask: Long) = SymbolOps(isFlagRelated = true, mask = mask)
+
+ private def relevantSymbols(syms: Seq[Symbol]) = syms.flatMap(sym => List(sym, sym.moduleClass, sym.sourceModule))
+ def markFlagsCompleted(syms: Symbol*)(mask: Long): Unit = relevantSymbols(syms).foreach(_.markFlagsCompleted(mask))
+ def markAllCompleted(syms: Symbol*): Unit = relevantSymbols(syms).foreach(_.markAllCompleted)
}
object SymbolsStats {
diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala
index c1753fc5a1..9066c73393 100644
--- a/src/reflect/scala/reflect/internal/TreeGen.scala
+++ b/src/reflect/scala/reflect/internal/TreeGen.scala
@@ -1,7 +1,12 @@
-package scala.reflect
+package scala
+package reflect
package internal
-abstract class TreeGen extends macros.TreeBuilder {
+import Flags._
+import util._
+import scala.collection.mutable.ListBuffer
+
+abstract class TreeGen {
val global: SymbolTable
import global._
@@ -11,10 +16,7 @@ abstract class TreeGen extends macros.TreeBuilder {
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 scalaAnyRefConstr = scalaDot(tpnme.AnyRef) // used in ide
def scalaFunctionConstr(argtpes: List[Tree], restpe: Tree, abstractFun: Boolean = false): Tree = {
val cls = if (abstractFun)
@@ -47,10 +49,10 @@ abstract class TreeGen extends macros.TreeBuilder {
mkMethodCall(Select(receiver, method), targs, args)
def mkMethodCall(target: Tree, targs: List[Type], args: List[Tree]): Tree =
- Apply(mkTypeApply(target, targs map TypeTree), args)
+ Apply(mkTypeApply(target, mapList(targs)(TypeTree)), args)
def mkNullaryCall(method: Symbol, targs: List[Type]): Tree =
- mkTypeApply(mkAttributedRef(method), targs map TypeTree)
+ mkTypeApply(mkAttributedRef(method), mapList(targs)(TypeTree))
/** Builds a reference to value whose type is given stable prefix.
* The type must be suitable for this. For example, it
@@ -93,7 +95,7 @@ abstract class TreeGen extends macros.TreeBuilder {
case ConstantType(value) =>
Literal(value) setType tpe
- case AnnotatedType(_, atp, _) =>
+ case AnnotatedType(_, atp) =>
mkAttributedQualifier(atp)
case RefinedType(parents, _) =>
@@ -116,7 +118,7 @@ abstract class TreeGen extends macros.TreeBuilder {
}
/** Builds a reference to given symbol with given stable prefix. */
- def mkAttributedRef(pre: Type, sym: Symbol): Tree = {
+ def mkAttributedRef(pre: Type, sym: Symbol): RefTree = {
val qual = mkAttributedQualifier(pre)
qual match {
case EmptyTree => mkAttributedIdent(sym)
@@ -126,33 +128,33 @@ abstract class TreeGen extends macros.TreeBuilder {
}
/** Builds a reference to given symbol. */
- def mkAttributedRef(sym: Symbol): Tree =
+ def mkAttributedRef(sym: Symbol): RefTree =
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)
+ def mkUnattributedRef(sym: Symbol): RefTree = mkUnattributedRef(sym.fullNameAsName('.'))
+
+ def mkUnattributedRef(fullName: Name): RefTree = {
+ val hd :: tl = nme.segments(fullName.toString, assumeTerm = fullName.isTermName)
+ tl.foldLeft(Ident(hd): RefTree)(Select(_,_))
+ }
/** Replaces tree type with a stable type if possible */
- def stabilize(tree: Tree): Tree = {
- for(tp <- stableTypeFor(tree)) tree.tpe = tp
- tree
+ def stabilize(tree: Tree): Tree = stableTypeFor(tree) match {
+ case NoType => tree
+ case tp => tree setType tp
}
/** Computes stable type for a tree if possible */
- def stableTypeFor(tree: Tree): Option[Type] = tree match {
- case This(_) if tree.symbol != null && !tree.symbol.isError =>
- Some(ThisType(tree.symbol))
- 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
- }
+ def stableTypeFor(tree: Tree): Type = (
+ if (!treeInfo.admitsTypeSelection(tree)) NoType
+ else tree match {
+ case This(_) => ThisType(tree.symbol)
+ case Ident(_) => singleType(tree.symbol.owner.thisType, tree.symbol)
+ case Select(qual, _) => singleType(qual.tpe, tree.symbol)
+ case _ => NoType
+ }
+ )
/** Builds a reference with stable type to given symbol */
def mkAttributedStableRef(pre: Type, sym: Symbol): Tree =
@@ -161,13 +163,13 @@ abstract class TreeGen extends macros.TreeBuilder {
def mkAttributedStableRef(sym: Symbol): Tree =
stabilize(mkAttributedRef(sym))
- def mkAttributedThis(sym: Symbol): Tree =
+ def mkAttributedThis(sym: Symbol): This =
This(sym.name.toTypeName) setSymbol sym setType sym.thisType
- def mkAttributedIdent(sym: Symbol): Tree =
- Ident(sym.name) setSymbol sym setType sym.tpe
+ def mkAttributedIdent(sym: Symbol): RefTree =
+ Ident(sym.name) setSymbol sym setType sym.tpeHK
- def mkAttributedSelect(qual: Tree, sym: Symbol): Tree = {
+ def mkAttributedSelect(qual: Tree, sym: Symbol): RefTree = {
// Tests involving the repl fail without the .isEmptyPackage condition.
if (qual.symbol != null && (qual.symbol.isEffectiveRoot || qual.symbol.isEmptyPackage))
mkAttributedIdent(sym)
@@ -184,16 +186,12 @@ abstract class TreeGen extends macros.TreeBuilder {
)
val needsPackageQualifier = (
(sym ne null)
- && qualsym.isPackage
- && !sym.isDefinedInPackage
+ && qualsym.hasPackageFlag
+ && !(sym.isDefinedInPackage || sym.moduleClass.isDefinedInPackage) // SI-7817 work around strangeness in post-flatten `Symbol#owner`
)
val pkgQualifier =
if (needsPackageQualifier) {
- // The owner of a symbol which requires package qualification may be the
- // package object iself, but it also could be any superclass of the package
- // object. In the latter case, we must go through the qualifier's info
- // to obtain the right symbol.
- val packageObject = if (sym.owner.isModuleClass) sym.owner.sourceModule else qual.tpe member nme.PACKAGE
+ val packageObject = rootMirror.getPackageObjectWithMember(qual.tpe, sym)
Select(qual, nme.PACKAGE) setSymbol packageObject setType singleType(qual.tpe, packageObject)
}
else qual
@@ -207,13 +205,13 @@ abstract class TreeGen extends macros.TreeBuilder {
/** 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 mkAppliedTypeTree(fun: Tree, targs: List[Tree]): Tree =
+ if (targs.isEmpty) fun else AppliedTypeTree(fun, targs)
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, tpe.normalize :: Nil)
+ val tapp = mkAttributedTypeApply(value, what, tpe.dealias :: Nil)
if (wrapInApply) Apply(tapp, Nil) else tapp
}
private def typeTestSymbol(any: Boolean) = if (any) Any_isInstanceOf else Object_isInstanceOf
@@ -229,7 +227,7 @@ abstract class TreeGen extends macros.TreeBuilder {
/** 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
+ if ((pt == UnitTpe) || (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))
@@ -248,10 +246,6 @@ abstract class TreeGen extends macros.TreeBuilder {
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
@@ -259,7 +253,7 @@ abstract class TreeGen extends macros.TreeBuilder {
* which is appropriate to the given Type.
*/
def mkZero(tp: Type): Tree = tp.typeSymbol match {
- case NothingClass => mkMethodCall(Predef_???, Nil) setType NothingClass.tpe
+ case NothingClass => mkMethodCall(Predef_???, Nil) setType NothingTpe
case _ => Literal(mkConstantZero(tp)) setType tp
}
@@ -276,12 +270,28 @@ abstract class TreeGen extends macros.TreeBuilder {
case _ => Constant(null)
}
+ /** Wrap an expression in a named argument. */
+ def mkNamedArg(name: Name, tree: Tree): Tree = mkNamedArg(Ident(name), tree)
+ def mkNamedArg(lhs: Tree, rhs: Tree): Tree = atPos(rhs.pos)(AssignOrNamedArg(lhs, rhs))
+
/** 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)
+ def mkTuple(elems: List[Tree], flattenUnary: Boolean = true): Tree = elems match {
+ case Nil =>
+ Literal(Constant(()))
+ case tree :: Nil if flattenUnary =>
+ tree
+ case _ =>
+ Apply(scalaDot(TupleClass(elems.length).name.toTermName), elems)
+ }
+
+ def mkTupleType(elems: List[Tree], flattenUnary: Boolean = true): Tree = elems match {
+ case Nil =>
+ scalaDot(tpnme.Unit)
+ case List(tree) if flattenUnary =>
+ tree
+ case _ =>
+ AppliedTypeTree(scalaDot(TupleClass(elems.length).name), elems)
+ }
// tree1 AND tree2
def mkAnd(tree1: Tree, tree2: Tree): Tree =
@@ -295,4 +305,595 @@ abstract class TreeGen extends macros.TreeBuilder {
assert(ReflectRuntimeUniverse != NoSymbol)
mkAttributedRef(ReflectRuntimeUniverse) setType singleType(ReflectRuntimeUniverse.owner.thisPrefix, ReflectRuntimeUniverse)
}
+
+ def mkSeqApply(arg: Tree): Apply = {
+ val factory = Select(mkAttributedRef(SeqModule), nme.apply)
+ Apply(factory, List(arg))
+ }
+
+ def mkSuperInitCall: Select = Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR)
+
+ /** Generates a template with constructor corresponding to
+ *
+ * constrmods (vparams1_) ... (vparams_n) preSuper { presupers }
+ * extends superclass(args_1) ... (args_n) with mixins { self => body }
+ *
+ * This gets translated to
+ *
+ * extends superclass with mixins { self =>
+ * presupers' // presupers without rhs
+ * vparamss // abstract fields corresponding to value parameters
+ * def <init>(vparamss) {
+ * presupers
+ * super.<init>(args)
+ * }
+ * body
+ * }
+ */
+ def mkTemplate(parents: List[Tree], self: ValDef, constrMods: Modifiers,
+ vparamss: List[List[ValDef]], body: List[Tree], superPos: Position = NoPosition): Template = {
+ /* Add constructor to template */
+
+ // create parameters for <init> as synthetic trees.
+ var vparamss1 = mmap(vparamss) { vd =>
+ val param = atPos(vd.pos.makeTransparent) {
+ val mods = Modifiers(vd.mods.flags & (IMPLICIT | DEFAULTPARAM | BYNAMEPARAM) | PARAM | PARAMACCESSOR)
+ ValDef(mods withAnnotations vd.mods.annotations, vd.name, vd.tpt.duplicate, duplicateAndKeepPositions(vd.rhs))
+ }
+ param
+ }
+
+ val (edefs, rest) = body span treeInfo.isEarlyDef
+ val (evdefs, etdefs) = edefs partition treeInfo.isEarlyValDef
+ val gvdefs = evdefs map {
+ case vdef @ ValDef(_, _, tpt, _) =>
+ copyValDef(vdef)(
+ // atPos for the new tpt is necessary, since the original tpt might have no position
+ // (when missing type annotation for ValDef for example), so even though setOriginal modifies the
+ // position of TypeTree, it would still be NoPosition. That's what the author meant.
+ tpt = atPos(vdef.pos.focus)(TypeTree() setOriginal tpt setPos tpt.pos.focus),
+ rhs = EmptyTree
+ )
+ }
+ val lvdefs = evdefs collect { case vdef: ValDef => copyValDef(vdef)(mods = vdef.mods | PRESUPER) }
+
+ val constr = {
+ if (constrMods.isTrait) {
+ if (body forall treeInfo.isInterfaceMember) None
+ else Some(
+ atPos(wrappingPos(superPos, lvdefs)) (
+ DefDef(NoMods, nme.MIXIN_CONSTRUCTOR, Nil, ListOfNil, TypeTree(), Block(lvdefs, Literal(Constant())))))
+ }
+ else {
+ // convert (implicit ... ) to ()(implicit ... ) if its the only parameter section
+ if (vparamss1.isEmpty || !vparamss1.head.isEmpty && vparamss1.head.head.mods.isImplicit)
+ vparamss1 = List() :: vparamss1
+ val superCall = pendingSuperCall // we can't know in advance which of the parents will end up as a superclass
+ // this requires knowing which of the parents is a type macro and which is not
+ // and that's something that cannot be found out before typer
+ // (the type macros aren't in the trunk yet, but there is a plan for them to land there soon)
+ // this means that we don't know what will be the arguments of the super call
+ // therefore here we emit a dummy which gets populated when the template is named and typechecked
+ Some(
+ atPos(wrappingPos(superPos, lvdefs ::: vparamss1.flatten).makeTransparent) (
+ DefDef(constrMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), Block(lvdefs ::: List(superCall), Literal(Constant())))))
+ }
+ }
+ constr foreach (ensureNonOverlapping(_, parents ::: gvdefs, focus = false))
+ // Field definitions for the class - remove defaults.
+
+ val fieldDefs = vparamss.flatten map (vd => {
+ val field = copyValDef(vd)(mods = vd.mods &~ DEFAULTPARAM, rhs = EmptyTree)
+ // Prevent overlapping of `field` end's position with default argument's start position.
+ // This is needed for `Positions.Locator(pos).traverse` to return the correct tree when
+ // the `pos` is a point position with all its values equal to `vd.rhs.pos.start`.
+ if(field.pos.isRange && vd.rhs.pos.isRange) field.pos = field.pos.withEnd(vd.rhs.pos.start - 1)
+ field
+ })
+
+ global.Template(parents, self, gvdefs ::: fieldDefs ::: constr ++: etdefs ::: rest)
+ }
+
+ def mkParents(ownerMods: Modifiers, parents: List[Tree], parentPos: Position = NoPosition) =
+ if (ownerMods.isCase) parents ::: List(scalaDot(tpnme.Product), scalaDot(tpnme.Serializable))
+ else if (parents.isEmpty) atPos(parentPos)(scalaAnyRefConstr) :: Nil
+ else parents
+
+ def mkClassDef(mods: Modifiers, name: TypeName, tparams: List[TypeDef], templ: Template): ClassDef = {
+ val isInterface = mods.isTrait && (templ.body forall treeInfo.isInterfaceMember)
+ val mods1 = if (isInterface) (mods | Flags.INTERFACE) else mods
+ ClassDef(mods1, name, tparams, templ)
+ }
+
+ /** Create positioned tree representing an object creation <new parents { stats }
+ * @param npos the position of the new
+ * @param cpos the position of the anonymous class starting with parents
+ */
+ def mkNew(parents: List[Tree], self: ValDef, stats: List[Tree],
+ npos: Position, cpos: Position): Tree =
+ if (parents.isEmpty)
+ mkNew(List(scalaAnyRefConstr), self, stats, npos, cpos)
+ else if (parents.tail.isEmpty && stats.isEmpty) {
+ // `Parsers.template` no longer differentiates tpts and their argss
+ // e.g. `C()` will be represented as a single tree Apply(Ident(C), Nil)
+ // instead of parents = Ident(C), argss = Nil as before
+ // this change works great for things that are actually templates
+ // but in this degenerate case we need to perform postprocessing
+ val app = treeInfo.dissectApplied(parents.head)
+ atPos(npos union cpos) { New(app.callee, app.argss) }
+ } else {
+ val x = tpnme.ANON_CLASS_NAME
+ atPos(npos union cpos) {
+ Block(
+ List(
+ atPos(cpos) {
+ ClassDef(
+ Modifiers(FINAL), x, Nil,
+ mkTemplate(parents, self, NoMods, ListOfNil, stats, cpos.focus))
+ }),
+ atPos(npos) {
+ New(
+ Ident(x) setPos npos.focus,
+ Nil)
+ }
+ )
+ }
+ }
+
+ /** Create a tree representing the function type (argtpes) => restpe */
+ def mkFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree =
+ AppliedTypeTree(rootScalaDot(newTypeName("Function" + argtpes.length)), argtpes ::: List(restpe))
+
+ /** Create a literal unit tree that is inserted by the compiler but not
+ * written by end user. It's important to distinguish the two so that
+ * quasiquotes can strip synthetic ones away.
+ */
+ def mkSyntheticUnit() = Literal(Constant(())).updateAttachment(SyntheticUnitAttachment)
+
+ /** Create block of statements `stats` */
+ def mkBlock(stats: List[Tree]): Tree =
+ if (stats.isEmpty) mkSyntheticUnit()
+ else if (!stats.last.isTerm) Block(stats, mkSyntheticUnit())
+ else if (stats.length == 1) stats.head
+ else Block(stats.init, stats.last)
+
+ /** Create a block that wraps multiple statements but don't
+ * do any wrapping if there is just one statement. Used by
+ * quasiquotes, macro c.parse api and toolbox.
+ */
+ def mkTreeOrBlock(stats: List[Tree]) = stats match {
+ case Nil => EmptyTree
+ case head :: Nil => head
+ case _ => mkBlock(stats)
+ }
+
+ /** Create a tree representing an assignment <lhs = rhs> */
+ def mkAssign(lhs: Tree, rhs: Tree): Tree = lhs match {
+ case Apply(fn, args) => Apply(atPos(fn.pos)(Select(fn, nme.update)), args :+ rhs)
+ case _ => Assign(lhs, rhs)
+ }
+
+ def mkPackageObject(defn: ModuleDef, pidPos: Position = NoPosition, pkgPos: Position = NoPosition) = {
+ val module = copyModuleDef(defn)(name = nme.PACKAGEkw)
+ val pid = atPos(pidPos)(Ident(defn.name))
+ atPos(pkgPos)(PackageDef(pid, module :: Nil))
+ }
+
+ // Following objects represent encoding of for loop enumerators
+ // into the regular trees. Such representations are used for:
+ //
+ // - as intermediate value of enumerators inside of the parser
+ // right before the mkFor desugaring is being called
+ //
+ // - as intermediate value of enumerators obtained after
+ // re-sugaring of for loops through build.SyntacticFor
+ // and build.SyntacticForYield (which are used by quasiquotes)
+ //
+ // The encoding uses regular trees with ForAttachment that helps
+ // to reliably differentiate them from normal trees that can have
+ // similar shape. fq"$pat <- $rhs" for example is represented in
+ // the same way as "`<-`($pat, $rhs)"" but with added attachment to
+ // the `<-` identifier.
+ //
+ // The primary rationale behind such representation in favor of
+ // simple case classes is a wish to re-use the same representation
+ // between quasiquotes and parser without exposing compiler internals.
+ // Opaque tree encoding can be changed/adapted at any time without
+ // breaking end users code.
+
+ /** Encode/decode fq"$pat <- $rhs" enumerator as q"`<-`($pat, $rhs)" */
+ object ValFrom {
+ def apply(pat: Tree, rhs: Tree): Tree =
+ Apply(Ident(nme.LARROWkw).updateAttachment(ForAttachment),
+ List(pat, rhs))
+
+ def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
+ case Apply(id @ Ident(nme.LARROWkw), List(pat, rhs))
+ if id.hasAttachment[ForAttachment.type] =>
+ Some((pat, rhs))
+ case _ => None
+ }
+ }
+
+ /** Encode/decode fq"$pat = $rhs" enumerator as q"$pat = $rhs" */
+ object ValEq {
+ def apply(pat: Tree, rhs: Tree): Tree =
+ Assign(pat, rhs).updateAttachment(ForAttachment)
+
+ def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
+ case Assign(pat, rhs)
+ if tree.hasAttachment[ForAttachment.type] =>
+ Some((pat, rhs))
+ case _ => None
+ }
+ }
+
+ /** Encode/decode fq"if $cond" enumerator as q"`if`($cond)" */
+ object Filter {
+ def apply(tree: Tree) =
+ Apply(Ident(nme.IFkw).updateAttachment(ForAttachment), List(tree))
+
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ case Apply(id @ Ident(nme.IFkw), List(cond))
+ if id.hasAttachment[ForAttachment.type] =>
+ Some((cond))
+ case _ => None
+ }
+ }
+
+ /** Encode/decode body of for yield loop as q"`yield`($tree)" */
+ object Yield {
+ def apply(tree: Tree): Tree =
+ Apply(Ident(nme.YIELDkw).updateAttachment(ForAttachment), List(tree))
+
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ case Apply(id @ Ident(nme.YIELDkw), List(tree))
+ if id.hasAttachment[ForAttachment.type] =>
+ Some(tree)
+ case _ => None
+ }
+ }
+
+ /** Create tree for for-comprehension <for (enums) do body> or
+ * <for (enums) yield body> where mapName and flatMapName are chosen
+ * corresponding to whether this is a for-do or a for-yield.
+ * The creation performs the following rewrite rules:
+ *
+ * 1.
+ *
+ * for (P <- G) E ==> G.foreach (P => E)
+ *
+ * Here and in the following (P => E) is interpreted as the function (P => E)
+ * if P is a variable pattern and as the partial function { case P => E } otherwise.
+ *
+ * 2.
+ *
+ * for (P <- G) yield E ==> G.map (P => E)
+ *
+ * 3.
+ *
+ * for (P_1 <- G_1; P_2 <- G_2; ...) ...
+ * ==>
+ * G_1.flatMap (P_1 => for (P_2 <- G_2; ...) ...)
+ *
+ * 4.
+ *
+ * for (P <- G; E; ...) ...
+ * =>
+ * for (P <- G.filter (P => E); ...) ...
+ *
+ * 5. For N < MaxTupleArity:
+ *
+ * for (P_1 <- G; P_2 = E_2; val P_N = E_N; ...)
+ * ==>
+ * for (TupleN(P_1, P_2, ... P_N) <-
+ * for (x_1 @ P_1 <- G) yield {
+ * val x_2 @ P_2 = E_2
+ * ...
+ * val x_N & P_N = E_N
+ * TupleN(x_1, ..., x_N)
+ * } ...)
+ *
+ * If any of the P_i are variable patterns, the corresponding `x_i @ P_i' is not generated
+ * and the variable constituting P_i is used instead of x_i
+ *
+ * @param mapName The name to be used for maps (either map or foreach)
+ * @param flatMapName The name to be used for flatMaps (either flatMap or foreach)
+ * @param enums The enumerators in the for expression
+ * @param body The body of the for expression
+ */
+ def mkFor(enums: List[Tree], sugarBody: Tree)(implicit fresh: FreshNameCreator): Tree = {
+ val (mapName, flatMapName, body) = sugarBody match {
+ case Yield(tree) => (nme.map, nme.flatMap, tree)
+ case _ => (nme.foreach, nme.foreach, sugarBody)
+ }
+
+ /* make a closure pat => body.
+ * The closure is assigned a transparent position with the point at pos.point and
+ * the limits given by pat and body.
+ */
+ def makeClosure(pos: Position, pat: Tree, body: Tree): Tree = {
+ def wrapped = wrappingPos(List(pat, body))
+ def splitpos = (if (pos != NoPosition) wrapped.withPoint(pos.point) else pos).makeTransparent
+ matchVarPattern(pat) match {
+ case Some((name, tpt)) =>
+ Function(
+ List(atPos(pat.pos) { ValDef(Modifiers(PARAM), name.toTermName, tpt, EmptyTree) }),
+ body) setPos splitpos
+ case None =>
+ atPos(splitpos) {
+ mkVisitor(List(CaseDef(pat, EmptyTree, body)), checkExhaustive = false)
+ }
+ }
+ }
+
+ /* Make an application qual.meth(pat => body) positioned at `pos`.
+ */
+ def makeCombination(pos: Position, meth: TermName, qual: Tree, pat: Tree, body: Tree): Tree =
+ // ForAttachment on the method selection is used to differentiate
+ // result of for desugaring from a regular method call
+ Apply(Select(qual, meth) setPos qual.pos updateAttachment ForAttachment,
+ List(makeClosure(pos, pat, body))) setPos pos
+
+ /* If `pat` is not yet a `Bind` wrap it in one with a fresh name */
+ def makeBind(pat: Tree): Tree = pat match {
+ case Bind(_, _) => pat
+ case _ => Bind(freshTermName(), pat) setPos pat.pos
+ }
+
+ /* A reference to the name bound in Bind `pat`. */
+ def makeValue(pat: Tree): Tree = pat match {
+ case Bind(name, _) => Ident(name) setPos pat.pos.focus
+ }
+
+ /* The position of the closure that starts with generator at position `genpos`. */
+ def closurePos(genpos: Position) =
+ if (genpos == NoPosition) NoPosition
+ else {
+ val end = body.pos match {
+ case NoPosition => genpos.point
+ case bodypos => bodypos.end
+ }
+ rangePos(genpos.source, genpos.start, genpos.point, end)
+ }
+
+ enums match {
+ case (t @ ValFrom(pat, rhs)) :: Nil =>
+ makeCombination(closurePos(t.pos), mapName, rhs, pat, body)
+ case (t @ ValFrom(pat, rhs)) :: (rest @ (ValFrom(_, _) :: _)) =>
+ makeCombination(closurePos(t.pos), flatMapName, rhs, pat,
+ mkFor(rest, sugarBody))
+ case (t @ ValFrom(pat, rhs)) :: Filter(test) :: rest =>
+ mkFor(ValFrom(pat, makeCombination(rhs.pos union test.pos, nme.withFilter, rhs, pat.duplicate, test)).setPos(t.pos) :: rest, sugarBody)
+ case (t @ ValFrom(pat, rhs)) :: rest =>
+ val valeqs = rest.take(definitions.MaxTupleArity - 1).takeWhile { ValEq.unapply(_).nonEmpty }
+ assert(!valeqs.isEmpty)
+ val rest1 = rest.drop(valeqs.length)
+ val pats = valeqs map { case ValEq(pat, _) => pat }
+ val rhss = valeqs map { case ValEq(_, rhs) => rhs }
+ val defpat1 = makeBind(pat)
+ val defpats = pats map makeBind
+ val pdefs = (defpats, rhss).zipped flatMap mkPatDef
+ val ids = (defpat1 :: defpats) map makeValue
+ val rhs1 = mkFor(
+ List(ValFrom(defpat1, rhs).setPos(t.pos)),
+ Yield(Block(pdefs, atPos(wrappingPos(ids)) { mkTuple(ids) }) setPos wrappingPos(pdefs)))
+ val allpats = (pat :: pats) map (_.duplicate)
+ val pos1 =
+ if (t.pos == NoPosition) NoPosition
+ else rangePos(t.pos.source, t.pos.start, t.pos.point, rhs1.pos.end)
+ val vfrom1 = ValFrom(atPos(wrappingPos(allpats)) { mkTuple(allpats) }, rhs1).setPos(pos1)
+ mkFor(vfrom1 :: rest1, sugarBody)
+ case _ =>
+ EmptyTree //may happen for erroneous input
+
+ }
+ }
+
+ /** Create tree for pattern definition <val pat0 = rhs> */
+ def mkPatDef(pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator): List[ValDef] =
+ mkPatDef(Modifiers(0), pat, rhs)
+
+ /** Create tree for pattern definition <mods val pat0 = rhs> */
+ def mkPatDef(mods: Modifiers, pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator): List[ValDef] = matchVarPattern(pat) match {
+ case Some((name, tpt)) =>
+ List(atPos(pat.pos union rhs.pos) {
+ ValDef(mods, name.toTermName, tpt, rhs)
+ })
+
+ case None =>
+ // in case there is exactly one variable x_1 in pattern
+ // val/var p = e ==> val/var x_1 = e.match (case p => (x_1))
+ //
+ // in case there are zero or more than one variables in pattern
+ // val/var p = e ==> private synthetic val t$ = e.match (case p => (x_1, ..., x_N))
+ // val/var x_1 = t$._1
+ // ...
+ // val/var x_N = t$._N
+
+ val rhsUnchecked = mkUnchecked(rhs)
+
+ // TODO: clean this up -- there is too much information packked into mkPatDef's `pat` argument
+ // when it's a simple identifier (case Some((name, tpt)) -- above),
+ // pat should have the type ascription that was specified by the user
+ // however, in `case None` (here), we must be careful not to generate illegal pattern trees (such as `(a, b): Tuple2[Int, String]`)
+ // i.e., this must hold: pat1 match { case Typed(expr, tp) => assert(expr.isInstanceOf[Ident]) case _ => }
+ // if we encounter such an erroneous pattern, we strip off the type ascription from pat and propagate the type information to rhs
+ val (pat1, rhs1) = patvarTransformer.transform(pat) match {
+ // move the Typed ascription to the rhs
+ case Typed(expr, tpt) if !expr.isInstanceOf[Ident] =>
+ val rhsTypedUnchecked =
+ if (tpt.isEmpty) rhsUnchecked
+ else Typed(rhsUnchecked, tpt) setPos (rhs.pos union tpt.pos)
+ (expr, rhsTypedUnchecked)
+ case ok =>
+ (ok, rhsUnchecked)
+ }
+ val vars = getVariables(pat1)
+ val matchExpr = atPos((pat1.pos union rhs.pos).makeTransparent) {
+ Match(
+ rhs1,
+ List(
+ atPos(pat1.pos) {
+ CaseDef(pat1, EmptyTree, mkTuple(vars map (_._1) map Ident.apply))
+ }
+ ))
+ }
+ vars match {
+ case List((vname, tpt, pos)) =>
+ List(atPos(pat.pos union pos union rhs.pos) {
+ ValDef(mods, vname.toTermName, tpt, matchExpr)
+ })
+ case _ =>
+ val tmp = freshTermName()
+ val firstDef =
+ atPos(matchExpr.pos) {
+ ValDef(Modifiers(PrivateLocal | SYNTHETIC | ARTIFACT | (mods.flags & LAZY)),
+ tmp, TypeTree(), matchExpr)
+ }
+ var cnt = 0
+ val restDefs = for ((vname, tpt, pos) <- vars) yield atPos(pos) {
+ cnt += 1
+ ValDef(mods, vname.toTermName, tpt, Select(Ident(tmp), newTermName("_" + cnt)))
+ }
+ firstDef :: restDefs
+ }
+ }
+
+ /** Create tree for for-comprehension generator <val pat0 <- rhs0> */
+ def mkGenerator(pos: Position, pat: Tree, valeq: Boolean, rhs: Tree)(implicit fresh: FreshNameCreator): Tree = {
+ val pat1 = patvarTransformer.transform(pat)
+ if (valeq) ValEq(pat1, rhs).setPos(pos)
+ else ValFrom(pat1, mkCheckIfRefutable(pat1, rhs)).setPos(pos)
+ }
+
+ def mkCheckIfRefutable(pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator) =
+ if (treeInfo.isVarPatternDeep(pat)) rhs
+ else {
+ val cases = List(
+ CaseDef(pat.duplicate, EmptyTree, Literal(Constant(true))),
+ CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false)))
+ )
+ val visitor = mkVisitor(cases, checkExhaustive = false, nme.CHECK_IF_REFUTABLE_STRING)
+ atPos(rhs.pos)(Apply(Select(rhs, nme.withFilter), visitor :: Nil))
+ }
+
+ /** If tree is a variable pattern, return Some("its name and type").
+ * Otherwise return none */
+ private def matchVarPattern(tree: Tree): Option[(Name, Tree)] = {
+ def wildType(t: Tree): Option[Tree] = t match {
+ case Ident(x) if x.toTermName == nme.WILDCARD => Some(TypeTree())
+ case Typed(Ident(x), tpt) if x.toTermName == nme.WILDCARD => Some(tpt)
+ case _ => None
+ }
+ tree match {
+ case Ident(name) => Some((name, TypeTree()))
+ case Bind(name, body) => wildType(body) map (x => (name, x))
+ case Typed(Ident(name), tpt) => Some((name, tpt))
+ case _ => None
+ }
+ }
+
+ /** Create visitor <x => x match cases> */
+ def mkVisitor(cases: List[CaseDef], checkExhaustive: Boolean, prefix: String = "x$")(implicit fresh: FreshNameCreator): Tree = {
+ val x = freshTermName(prefix)
+ val id = Ident(x)
+ val sel = if (checkExhaustive) id else mkUnchecked(id)
+ Function(List(mkSyntheticParam(x)), Match(sel, cases))
+ }
+
+ /** Traverse pattern and collect all variable names with their types in buffer
+ * The variables keep their positions; whereas the pattern is converted to be
+ * synthetic for all nodes that contain a variable position.
+ */
+ class GetVarTraverser extends Traverser {
+ val buf = new ListBuffer[(Name, Tree, Position)]
+
+ def namePos(tree: Tree, name: Name): Position =
+ if (!tree.pos.isRange || name.containsName(nme.raw.DOLLAR)) tree.pos.focus
+ else {
+ val start = tree.pos.start
+ val end = start + name.decode.length
+ rangePos(tree.pos.source, start, start, end)
+ }
+
+ override def traverse(tree: Tree): Unit = {
+ def seenName(name: Name) = buf exists (_._1 == name)
+ def add(name: Name, t: Tree) = if (!seenName(name)) buf += ((name, t, namePos(tree, name)))
+ val bl = buf.length
+
+ tree match {
+ case Bind(nme.WILDCARD, _) =>
+ super.traverse(tree)
+
+ case Bind(name, Typed(tree1, tpt)) =>
+ val newTree = if (treeInfo.mayBeTypePat(tpt)) TypeTree() else tpt.duplicate
+ add(name, newTree)
+ traverse(tree1)
+
+ case Bind(name, tree1) =>
+ // can assume only name range as position, as otherwise might overlap
+ // with binds embedded in pattern tree1
+ add(name, TypeTree())
+ traverse(tree1)
+
+ case _ =>
+ super.traverse(tree)
+ }
+ if (buf.length > bl)
+ tree setPos tree.pos.makeTransparent
+ }
+ def apply(tree: Tree) = {
+ traverse(tree)
+ buf.toList
+ }
+ }
+
+ /** Returns list of all pattern variables, possibly with their types,
+ * without duplicates
+ */
+ private def getVariables(tree: Tree): List[(Name, Tree, Position)] =
+ new GetVarTraverser apply tree
+
+ /** Convert all occurrences of (lower-case) variables in a pattern as follows:
+ * x becomes x @ _
+ * x: T becomes x @ (_: T)
+ */
+ object patvarTransformer extends Transformer {
+ override def transform(tree: Tree): Tree = tree match {
+ case Ident(name) if (treeInfo.isVarPattern(tree) && name != nme.WILDCARD) =>
+ atPos(tree.pos)(Bind(name, atPos(tree.pos.focus) (Ident(nme.WILDCARD))))
+ case Typed(id @ Ident(name), tpt) if (treeInfo.isVarPattern(id) && name != nme.WILDCARD) =>
+ atPos(tree.pos.withPoint(id.pos.point)) {
+ Bind(name, atPos(tree.pos.withStart(tree.pos.point)) {
+ Typed(Ident(nme.WILDCARD), tpt)
+ })
+ }
+ case Apply(fn @ Apply(_, _), args) =>
+ treeCopy.Apply(tree, transform(fn), transformTrees(args))
+ case Apply(fn, args) =>
+ treeCopy.Apply(tree, fn, transformTrees(args))
+ case Typed(expr, tpt) =>
+ treeCopy.Typed(tree, transform(expr), tpt)
+ case Bind(name, body) =>
+ treeCopy.Bind(tree, name, transform(body))
+ case Alternative(_) | Star(_) =>
+ super.transform(tree)
+ case _ =>
+ tree
+ }
+ }
+
+ // annotate the expression with @unchecked
+ def mkUnchecked(expr: Tree): Tree = atPos(expr.pos) {
+ // This can't be "Annotated(New(UncheckedClass), expr)" because annotations
+ // are very picky about things and it crashes the compiler with "unexpected new".
+ Annotated(New(scalaDot(tpnme.unchecked), Nil), expr)
+ }
+
+ def mkSyntheticParam(pname: TermName) =
+ ValDef(Modifiers(PARAM | SYNTHETIC), pname, TypeTree(), EmptyTree)
+
+ def mkCast(tree: Tree, pt: Type): Tree =
+ atPos(tree.pos)(mkAsInstanceOf(tree, pt, any = true, wrapInApply = false))
}
diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala
index a6556fc22d..b7d7d4df88 100644
--- a/src/reflect/scala/reflect/internal/TreeInfo.scala
+++ b/src/reflect/scala/reflect/internal/TreeInfo.scala
@@ -3,7 +3,8 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
import Flags._
@@ -17,7 +18,7 @@ abstract class TreeInfo {
val global: SymbolTable
import global._
- import definitions.{ isTupleSymbol, isVarArgsList, isCastSymbol, ThrowableClass, TupleClass, MacroContextClass, MacroContextPrefixType }
+ import definitions.{ isTupleSymbol, isVarArgsList, isCastSymbol, ThrowableClass, TupleClass, uncheckedStableClass, isBlackboxMacroBundleType, isWhiteboxContextType }
/* Does not seem to be used. Not sure what it does anyway.
def isOwnerDefinition(tree: Tree): Boolean = tree match {
@@ -70,6 +71,90 @@ abstract class TreeInfo {
false
}
+ /** Is `tree` a path, defined as follows? (Spec: 3.1 Paths)
+ *
+ * - The empty path ε (which cannot be written explicitly in user programs).
+ * - C.this, where C references a class.
+ * - p.x where p is a path and x is a stable member of p.
+ * - C.super.x or C.super[M].x where C references a class
+ * and x references a stable member of the super class or designated parent class M of C.
+ *
+ * NOTE: Trees with errors are (mostly) excluded.
+ *
+ * Path ::= StableId | [id ‘.’] this
+ *
+ */
+ def isPath(tree: Tree, allowVolatile: Boolean): Boolean =
+ tree match {
+ // Super is not technically a path.
+ // However, syntactically, it can only occur nested in a Select.
+ // This gives a nicer definition of isStableIdentifier that's equivalent to the spec's.
+ // must consider Literal(_) a path for typedSingletonTypeTree
+ case EmptyTree | Literal(_) => true
+ case This(_) | Super(_, _) => symOk(tree.symbol)
+ case _ => isStableIdentifier(tree, allowVolatile)
+ }
+
+ /** Is `tree` a stable identifier, a path which ends in an identifier?
+ *
+ * StableId ::= id
+ * | Path ‘.’ id
+ * | [id ’.’] ‘super’ [‘[’ id ‘]’] ‘.’ id
+ */
+ def isStableIdentifier(tree: Tree, allowVolatile: Boolean): Boolean =
+ tree match {
+ case i @ Ident(_) => isStableIdent(i, allowVolatile)
+ case Select(qual, _) => isStableMemberOf(tree.symbol, qual, allowVolatile) && isPath(qual, allowVolatile)
+ case Apply(Select(free @ Ident(_), nme.apply), _) if free.symbol.name endsWith nme.REIFY_FREE_VALUE_SUFFIX =>
+ // see a detailed explanation of this trick in `GenSymbols.reifyFreeTerm`
+ free.symbol.hasStableFlag && isPath(free, allowVolatile)
+ case _ => false
+ }
+
+ private def symOk(sym: Symbol) = sym != null && !sym.isError && sym != NoSymbol
+ private def typeOk(tp: Type) = tp != null && ! tp.isError
+
+ /** Assuming `sym` is a member of `tree`, is it a "stable member"?
+ *
+ * Stable members are packages or members introduced
+ * by object definitions or by value definitions of non-volatile types (§3.6).
+ */
+ def isStableMemberOf(sym: Symbol, tree: Tree, allowVolatile: Boolean): Boolean = (
+ symOk(sym) && (!sym.isTerm || (sym.isStable && (allowVolatile || !sym.hasVolatileType))) &&
+ typeOk(tree.tpe) && (allowVolatile || !hasVolatileType(tree)) && !definitions.isByNameParamType(tree.tpe)
+ )
+
+ private def isStableIdent(tree: Ident, allowVolatile: Boolean): Boolean = (
+ symOk(tree.symbol)
+ && tree.symbol.isStable
+ && !definitions.isByNameParamType(tree.tpe)
+ && (allowVolatile || !tree.symbol.hasVolatileType) // TODO SPEC: not required by spec
+ )
+
+ /** Is `tree`'s type volatile? (Ignored if its symbol has the @uncheckedStable annotation.)
+ */
+ def hasVolatileType(tree: Tree): Boolean =
+ symOk(tree.symbol) && tree.tpe.isVolatile && !tree.symbol.hasAnnotation(uncheckedStableClass)
+
+ /** Is `tree` either a non-volatile type,
+ * or a path that does not include any of:
+ * - a reference to a mutable variable/field
+ * - a reference to a by-name parameter
+ * - a member selection on a volatile type (Spec: 3.6 Volatile Types)?
+ *
+ * Such a tree is a suitable target for type selection.
+ */
+ def admitsTypeSelection(tree: Tree): Boolean = isPath(tree, allowVolatile = false)
+
+ /** Is `tree` admissible as a stable identifier pattern (8.1.5 Stable Identifier Patterns)?
+ *
+ * We disregard volatility, as it's irrelevant in patterns (SI-6815)
+ */
+ def isStableIdentifierPattern(tree: Tree): Boolean = isStableIdentifier(tree, allowVolatile = true)
+
+ // TODO SI-5304 tighten this up so we don't elide side effect in module loads
+ def isQualifierSafeToElide(tree: Tree): Boolean = isExprSafeToInline(tree)
+
/** Is tree an expression which can be inlined without affecting program semantics?
*
* Note that this is not called "isExprPure" since purity (lack of side-effects)
@@ -113,80 +198,70 @@ abstract class TreeInfo {
false
}
- @deprecated("Use isExprSafeToInline instead", "2.10.0")
- def isPureExpr(tree: Tree) = isExprSafeToInline(tree)
+ /** As if the name of the method didn't give it away,
+ * this logic is designed around issuing helpful
+ * warnings and minimizing spurious ones. That means
+ * don't reuse it for important matters like inlining
+ * decisions.
+ */
+ def isPureExprForWarningPurposes(tree: Tree): Boolean = tree match {
+ case Typed(expr, _) => isPureExprForWarningPurposes(expr)
+ case EmptyTree | Literal(Constant(())) => false
+ case _ =>
+ def isWarnableRefTree = tree match {
+ case t: RefTree => isExprSafeToInline(t.qualifier) && t.symbol != null && t.symbol.isAccessor
+ case _ => false
+ }
+ def isWarnableSymbol = {
+ val sym = tree.symbol
+ (sym == null) || !(sym.isModule || sym.isLazy || definitions.isByNameParamType(sym.tpe_*)) || {
+ debuglog("'Pure' but side-effecting expression in statement position: " + tree)
+ false
+ }
+ }
- def zipMethodParamsAndArgs(params: List[Symbol], args: List[Tree]): List[(Symbol, Tree)] =
- mapMethodParamsAndArgs(params, args)((param, arg) => ((param, arg)))
+ ( !tree.isErrorTyped
+ && (isExprSafeToInline(tree) || isWarnableRefTree)
+ && isWarnableSymbol
+ )
+ }
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
+ 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"
- )
+ global.devWarning(
+ s"""|Mismatch trying to zip method parameters and argument list:
+ | params = $params
+ | args = $args""".stripMargin)
false
}
if (plen == alen) foreach2(params, args)(f)
- else if (params.isEmpty) return fail
+ 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 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
+ 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 = dissectApplied(fn).applyDepth
- // 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 {
@@ -201,7 +276,7 @@ abstract class TreeInfo {
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
+ def isGetter = mayBeVarGetter(sym) && sym.owner.info.member(sym.setterName) != NoSymbol
tree match {
case Ident(_) => isVar
@@ -211,20 +286,24 @@ abstract class TreeInfo {
}
}
+ def isDefaultGetter(tree: Tree) = {
+ tree.symbol != null && tree.symbol.isDefaultGetter
+ }
+
/** Is tree a self constructor call this(...)? I.e. a call to a constructor of the
* same object?
*/
- def isSelfConstrCall(tree: Tree): Boolean = tree match {
- case Applied(Ident(nme.CONSTRUCTOR), _, _) => true
- case Applied(Select(This(_), nme.CONSTRUCTOR), _, _) => true
- case _ => false
+ def isSelfConstrCall(tree: Tree): Boolean = dissectApplied(tree).core match {
+ case Ident(nme.CONSTRUCTOR) => true
+ case Select(This(_), nme.CONSTRUCTOR) => true
+ case _ => false
}
/** Is tree a super constructor call?
*/
- def isSuperConstrCall(tree: Tree): Boolean = tree match {
- case Applied(Select(Super(_, _), nme.CONSTRUCTOR), _, _) => true
- case _ => false
+ def isSuperConstrCall(tree: Tree): Boolean = dissectApplied(tree).core match {
+ case Select(Super(_, _), nme.CONSTRUCTOR) => true
+ case _ => false
}
/**
@@ -330,9 +409,66 @@ abstract class TreeInfo {
case x: Ident => !x.isBackquoted && nme.isVariableName(x.name)
case _ => false
}
- def isDeprecatedIdentifier(tree: Tree): Boolean = tree match {
- case x: Ident => !x.isBackquoted && nme.isDeprecatedIdentifierName(x.name)
- case _ => false
+
+ /** Does the tree have a structure similar to typechecked trees? */
+ private[internal] def detectTypecheckedTree(tree: Tree) =
+ tree.hasExistingSymbol || tree.exists {
+ case dd: DefDef => dd.mods.hasAccessorFlag || dd.mods.isSynthetic // for untypechecked trees
+ case md: MemberDef => md.hasExistingSymbol
+ case _ => false
+ }
+
+ /** Recover template body to parsed state */
+ private[internal] def untypecheckedTemplBody(templ: Template) =
+ untypecheckedTreeBody(templ, templ.body)
+
+ /** Recover block body to parsed state */
+ private[internal] def untypecheckedBlockBody(block: Block) =
+ untypecheckedTreeBody(block, block.stats)
+
+ /** Recover tree body to parsed state */
+ private[internal] def untypecheckedTreeBody(tree: Tree, tbody: List[Tree]) = {
+ def filterBody(body: List[Tree]) = body filter {
+ case _: ValDef | _: TypeDef => true
+ // keep valdef or getter for val/var
+ case dd: DefDef if dd.mods.hasAccessorFlag => !nme.isSetterName(dd.name) && !tbody.exists {
+ case vd: ValDef => dd.name == vd.name.dropLocal
+ case _ => false
+ }
+ case md: MemberDef => !md.mods.isSynthetic
+ case tree => true
+ }
+
+ def lazyValDefRhs(body: Tree) =
+ body match {
+ case Block(List(Assign(_, rhs)), _) => rhs
+ case _ => body
+ }
+
+ def recoverBody(body: List[Tree]) = body map {
+ case vd @ ValDef(vmods, vname, _, vrhs) if nme.isLocalName(vname) =>
+ tbody find {
+ case dd: DefDef => dd.name == vname.dropLocal
+ case _ => false
+ } map { dd =>
+ val DefDef(dmods, dname, _, _, _, drhs) = dd
+ // get access flags from DefDef
+ val vdMods = (vmods &~ Flags.AccessFlags) | (dmods & Flags.AccessFlags).flags
+ // for most cases lazy body should be taken from accessor DefDef
+ val vdRhs = if (vmods.isLazy) lazyValDefRhs(drhs) else vrhs
+ copyValDef(vd)(mods = vdMods, name = dname, rhs = vdRhs)
+ } getOrElse (vd)
+ // for abstract and some lazy val/vars
+ case dd @ DefDef(mods, name, _, _, tpt, rhs) if mods.hasAccessorFlag =>
+ // transform getter mods to field
+ val vdMods = (if (!mods.hasStableFlag) mods | Flags.MUTABLE else mods &~ Flags.STABLE) &~ Flags.ACCESSOR
+ ValDef(vdMods, name, tpt, rhs)
+ case tr => tr
+ }
+
+ if (detectTypecheckedTree(tree)) {
+ recoverBody(filterBody(tbody))
+ } else tbody
}
/** The first constructor definitions in `stats` */
@@ -351,6 +487,9 @@ abstract class TreeInfo {
def preSuperFields(stats: List[Tree]): List[ValDef] =
stats collect { case vd: ValDef if isEarlyValDef(vd) => vd }
+ def hasUntypedPreSuperFields(stats: List[Tree]): Boolean =
+ preSuperFields(stats) exists (_.tpt.isEmpty)
+
def isEarlyDef(tree: Tree) = tree match {
case TypeDef(mods, _, _, _) => mods hasFlag PRESUPER
case ValDef(mods, _, _, _) => mods hasFlag PRESUPER
@@ -362,11 +501,6 @@ abstract class TreeInfo {
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)
@@ -389,15 +523,17 @@ abstract class TreeInfo {
case _ => false
}
+ /** Translates an Assign(_, _) node to AssignOrNamedArg(_, _) if
+ * the lhs is a simple ident. Otherwise returns unchanged.
+ */
+ def assignmentToMaybeNamedArg(tree: Tree) = tree match {
+ case t @ Assign(id: Ident, rhs) => atPos(t.pos)(AssignOrNamedArg(id, rhs))
+ case t => t
+ }
+
/** Is name a left-associative operator? */
def isLeftAssoc(operator: Name) = operator.nonEmpty && (operator.endChar != ':')
- /** 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
- }
-
/** a Match(Typed(_, tpt), _) must be translated into a switch if isSwitchAnnotation(tpt.tpe) */
def isSwitchAnnotation(tpe: Type) = tpe hasAnnotation definitions.SwitchClass
@@ -413,8 +549,15 @@ abstract class TreeInfo {
/** Is this argument node of the form <expr> : _* ?
*/
def isWildcardStarArg(tree: Tree): Boolean = tree match {
- case Typed(_, Ident(tpnme.WILDCARD_STAR)) => true
- case _ => false
+ case WildcardStarArg(_) => true
+ case _ => false
+ }
+
+ object WildcardStarArg {
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ case Typed(expr, Ident(tpnme.WILDCARD_STAR)) => Some(expr)
+ case _ => None
+ }
}
/** If this tree has type parameters, those. Otherwise Nil.
@@ -450,6 +593,8 @@ abstract class TreeInfo {
case _ => false
}
+ private def hasNoSymbol(t: Tree) = t.symbol == null || t.symbol == NoSymbol
+
/** Is this pattern node a synthetic catch-all case, added during PartialFuction synthesis before we know
* whether the user provided cases are exhaustive. */
def isSyntheticDefaultCase(cdef: CaseDef) = cdef match {
@@ -458,14 +603,19 @@ abstract class TreeInfo {
}
/** Does this CaseDef catch Throwable? */
- def catchesThrowable(cdef: CaseDef) = catchesAllOf(cdef, ThrowableClass.tpe)
+ def catchesThrowable(cdef: CaseDef) = (
+ cdef.guard.isEmpty && (unbind(cdef.pat) match {
+ case Ident(nme.WILDCARD) => true
+ case i@Ident(name) => hasNoSymbol(i)
+ case _ => false
+ })
+ )
- /** 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 CaseDef synthetically generated, e.g. by `MatchTranslation.translateTry`? */
+ def isSyntheticCase(cdef: CaseDef) = cdef.pat.exists {
+ case dt: DefTree => dt.symbol.isSynthetic
+ case _ => false
+ }
/** Is this pattern node a catch-all or type-test pattern? */
def isCatchCase(cdef: CaseDef) = cdef match {
@@ -490,7 +640,7 @@ abstract class TreeInfo {
tp match {
case TypeRef(pre, sym, args) =>
- args.isEmpty && (sym.owner.isPackageClass || isSimple(pre))
+ args.isEmpty && (sym.isTopLevel || isSimple(pre))
case NoPrefix =>
true
case _ =>
@@ -529,11 +679,12 @@ abstract class TreeInfo {
* case Extractor(a @ (b, c)) => 2
* }}}
*/
- def effectivePatternArity(args: List[Tree]): Int = (args.map(unbind) match {
- case Apply(fun, xs) :: Nil if isTupleSymbol(fun.symbol) => xs
- case xs => xs
- }).length
+ def effectivePatternArity(args: List[Tree]): Int = flattenedPatternArgs(args).length
+ def flattenedPatternArgs(args: List[Tree]): List[Tree] = args map unbind match {
+ case build.SyntacticTuple(xs) :: Nil => xs
+ case xs => xs
+ }
// used in the symbols for labeldefs and valdefs emitted by the pattern matcher
// tailcalls, cps,... use this flag combination to detect translated matches
@@ -543,6 +694,10 @@ abstract class TreeInfo {
def isSynthCaseSymbol(sym: Symbol) = sym hasAllFlags SYNTH_CASE_FLAGS
def hasSynthCaseSymbol(t: Tree) = t.symbol != null && isSynthCaseSymbol(t.symbol)
+ def isTraitRef(tree: Tree): Boolean = {
+ val sym = if (tree.tpe != null) tree.tpe.typeSymbol else null
+ ((sym ne null) && sym.initialize.isTrait)
+ }
/** Applications in Scala can have one of the following shapes:
*
@@ -625,19 +780,6 @@ abstract class TreeInfo {
}
loop(tree)
}
-
- /** The depth of the nested applies: e.g. Apply(Apply(Apply(_, _), _), _)
- * has depth 3. Continues through type applications (without counting them.)
- */
- def applyDepth: Int = {
- def loop(tree: Tree): Int = tree match {
- case Apply(fn, _) => 1 + loop(fn)
- case TypeApply(fn, _) => loop(fn)
- case AppliedTypeTree(fn, _) => loop(fn)
- case _ => 0
- }
- loop(tree)
- }
}
/** Returns a wrapper that knows how to destructure and analyze applications.
@@ -654,6 +796,8 @@ abstract class TreeInfo {
* For advanced use, call `dissectApplied` explicitly and use its methods instead of pattern matching.
*/
object Applied {
+ def apply(tree: Tree): Applied = new Applied(tree)
+
def unapply(applied: Applied): Option[(Tree, List[Tree], List[List[Tree]])] =
Some((applied.core, applied.targs, applied.argss))
@@ -665,13 +809,26 @@ abstract class TreeInfo {
* 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
- }
+ case Import(_, _) :: xs => firstDefinesClassOrObject(xs, name)
+ case Annotated(_, tree1) :: _ => firstDefinesClassOrObject(List(tree1), name)
+ case ModuleDef(_, `name`, _) :: _ => true
+ case ClassDef(_, `name`, _, _) :: _ => true
+ case _ => false
+ }
+ /** Locates the synthetic Apply node corresponding to an extractor's call to
+ * unapply (unwrapping nested Applies) and returns the fun part of that Apply.
+ */
+ object Unapplied {
+ // Duplicated with `spliceApply`
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ // SI-7868 Admit Select() to account for numeric widening, e.g. <unappplySelector>.toInt
+ case Apply(fun, (Ident(nme.SELECTOR_DUMMY)| Select(Ident(nme.SELECTOR_DUMMY), _)) :: Nil)
+ => Some(fun)
+ case Apply(fun, _) => unapply(fun)
+ case _ => None
+ }
+ }
/** Is this file the body of a compilation unit which should not
* have Predef imported?
@@ -726,12 +883,6 @@ abstract class TreeInfo {
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)
@@ -755,8 +906,24 @@ abstract class TreeInfo {
}
def unapply(tree: Tree) = refPart(tree) match {
- case ref: RefTree => Some((ref.qualifier.symbol, ref.symbol, dissectApplied(tree).targs))
- case _ => None
+ case ref: RefTree => {
+ val qual = ref.qualifier
+ val isBundle = definitions.isMacroBundleType(qual.tpe)
+ val isBlackbox =
+ if (isBundle) isBlackboxMacroBundleType(qual.tpe)
+ else ref.symbol.paramss match {
+ case (c :: Nil) :: _ if isWhiteboxContextType(c.info) => false
+ case _ => true
+ }
+ val owner =
+ if (isBundle) qual.tpe.typeSymbol
+ else {
+ val qualSym = if (qual.hasSymbolField) qual.symbol else NoSymbol
+ if (qualSym.isModule) qualSym.moduleClass else qualSym
+ }
+ Some((isBundle, isBlackbox, owner, ref.symbol, dissectApplied(tree).targs))
+ }
+ case _ => None
}
}
@@ -766,4 +933,14 @@ abstract class TreeInfo {
case tree: RefTree => true
case _ => false
})
+
+ def isMacroApplication(tree: Tree): Boolean = !tree.isDef && {
+ val sym = tree.symbol
+ sym != null && sym.isTermMacro && !sym.isErroneous
+ }
+
+ def isMacroApplicationOrBlock(tree: Tree): Boolean = tree match {
+ case Block(_, expr) => isMacroApplicationOrBlock(expr)
+ case tree => isMacroApplication(tree)
+ }
}
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index 0e5985face..9dc4baee32 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -3,17 +3,37 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
import Flags._
-import scala.collection.mutable.{ListBuffer, LinkedHashSet}
+import pickling.PickleFormat._
+import scala.collection.{ mutable, immutable }
import util.Statistics
-trait Trees extends api.Trees { self: SymbolTable =>
+trait Trees extends api.Trees {
+ self: SymbolTable =>
private[scala] var nodeCount = 0
+ protected def treeLine(t: Tree): String =
+ if (t.pos.isDefined && t.pos.isRange) t.pos.lineContent.drop(t.pos.column - 1).take(t.pos.end - t.pos.start + 1)
+ else t.summaryString
+
+ protected def treeStatus(t: Tree, enclosingTree: Tree = null) = {
+ val parent = if (enclosingTree eq null) " " else " P#%5s".format(enclosingTree.id)
+
+ "[L%4s%8s] #%-6s %-15s %-10s // %s".format(t.pos.line, parent, t.id, t.pos.show, t.shortClass, treeLine(t))
+ }
+ protected def treeSymStatus(t: Tree) = {
+ val line = if (t.pos.isDefined) "line %-4s".format(t.pos.line) else " "
+ "#%-5s %s %-10s // %s".format(t.id, line, t.shortClass,
+ if (t.symbol ne NoSymbol) "(" + t.symbol.fullLocationString + ")"
+ else treeLine(t)
+ )
+ }
+
abstract class Tree extends TreeContextApiImpl with Attachable with Product {
val id = nodeCount // TODO: add to attachment?
nodeCount += 1
@@ -24,18 +44,24 @@ trait Trees extends api.Trees { self: SymbolTable =>
private[this] var rawtpe: Type = _
final def tpe = rawtpe
- def tpe_=(t: Type) = rawtpe = t
+ @deprecated("Use setType", "2.11.0") def tpe_=(t: Type): Unit = setType(t)
+
+ def clearType(): this.type = this setType null
def setType(tp: Type): this.type = { rawtpe = tp; this }
def defineType(tp: Type): this.type = setType(tp)
def symbol: Symbol = null //!!!OPT!!! symbol is about 3% of hot compile times -- megamorphic dispatch?
def symbol_=(sym: Symbol) { throw new UnsupportedOperationException("symbol_= inapplicable for " + this) }
def setSymbol(sym: Symbol): this.type = { symbol = sym; this }
- def hasSymbol = false
+ def hasSymbolField = false
+ @deprecated("Use hasSymbolField", "2.11.0") def hasSymbol = hasSymbolField
def isDef = false
def isEmpty = false
+ def nonEmpty = !isEmpty
+
+ def canHaveAttrs = true
/** The canonical way to test if a Tree represents a term.
*/
@@ -62,7 +88,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
private[scala] def copyAttrs(tree: Tree): this.type = {
rawatt = tree.rawatt
tpe = tree.tpe
- if (hasSymbol) symbol = tree.symbol
+ if (hasSymbolField) symbol = tree.symbol
this
}
@@ -73,7 +99,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
(duplicator transform this).asInstanceOf[this.type]
}
- abstract class TreeContextApiImpl extends TreeContextApi { this: Tree =>
+ abstract class TreeContextApiImpl extends TreeApi { this: Tree =>
override def orElse(alt: => Tree) = if (!isEmpty) this else alt
@@ -132,11 +158,11 @@ trait Trees extends api.Trees { self: SymbolTable =>
productIterator.toList flatMap subtrees
}
- override def freeTerms: List[FreeTermSymbol] = freeSyms[FreeTermSymbol](_.isFreeTerm, _.termSymbol)
- override def freeTypes: List[FreeTypeSymbol] = freeSyms[FreeTypeSymbol](_.isFreeType, _.typeSymbol)
+ def freeTerms: List[FreeTermSymbol] = freeSyms[FreeTermSymbol](_.isFreeTerm, _.termSymbol)
+ def freeTypes: List[FreeTypeSymbol] = freeSyms[FreeTypeSymbol](_.isFreeType, _.typeSymbol)
private def freeSyms[S <: Symbol](isFree: Symbol => Boolean, symOfType: Type => Symbol): List[S] = {
- val s = scala.collection.mutable.LinkedHashSet[S]()
+ val s = mutable.LinkedHashSet[S]()
def addIfFree(sym: Symbol): Unit = if (sym != null && isFree(sym)) s += sym.asInstanceOf[S]
for (t <- this) {
addIfFree(t.symbol)
@@ -149,17 +175,17 @@ trait Trees extends api.Trees { self: SymbolTable =>
s.toList
}
- override def substituteSymbols(from: List[Symbol], to: List[Symbol]): Tree =
+ def substituteSymbols(from: List[Symbol], to: List[Symbol]): Tree =
new TreeSymSubstituter(from, to)(this)
- override def substituteTypes(from: List[Symbol], to: List[Type]): Tree =
+ def substituteTypes(from: List[Symbol], to: List[Type]): Tree =
new TreeTypeSubstituter(from, to)(this)
- override def substituteThis(clazz: Symbol, to: Tree): Tree =
+ def substituteThis(clazz: Symbol, to: Tree): Tree =
new ThisSubstituter(clazz, to) transform this
- def hasSymbolWhich(f: Symbol => Boolean) =
- (symbol ne null) && (symbol ne NoSymbol) && f(symbol)
+ def hasExistingSymbol = (symbol ne null) && (symbol ne NoSymbol)
+ def hasSymbolWhich(f: Symbol => Boolean) = hasExistingSymbol && f(symbol)
def isErroneous = (tpe ne null) && tpe.isErroneous
def isTyped = (tpe ne null) && !tpe.isErroneous
@@ -209,13 +235,16 @@ trait Trees extends api.Trees { self: SymbolTable =>
trait TypTree extends Tree with TypTreeApi
- abstract class SymTree extends Tree with SymTreeContextApi {
- override def hasSymbol = true
+ abstract class SymTree extends Tree with SymTreeApi {
+ override def hasSymbolField = true
override var symbol: Symbol = NoSymbol
}
trait NameTree extends Tree with NameTreeApi {
def name: Name
+ def getterName: TermName = name.getterName
+ def setterName: TermName = name.setterName
+ def localName: TermName = name.localName
}
trait RefTree extends SymTree with NameTree with RefTreeApi {
@@ -223,19 +252,24 @@ trait Trees extends api.Trees { self: SymbolTable =>
def name: Name
}
+ object RefTree extends RefTreeExtractor {
+ def apply(qualifier: Tree, name: Name): RefTree = qualifier match {
+ case EmptyTree =>
+ Ident(name)
+ case qual if qual.isTerm =>
+ Select(qual, name)
+ case qual if qual.isType =>
+ assert(name.isTypeName, s"qual = $qual, name = $name")
+ SelectFromTypeTree(qual, name.toTypeName)
+ }
+ def unapply(refTree: RefTree): Option[(Tree, Name)] = Some((refTree.qualifier, refTree.name))
+ }
+
abstract class DefTree extends SymTree with NameTree with DefTreeApi {
def name: Name
override def isDef = true
}
- case object EmptyTree extends TermTree {
- val asList = List(this)
- 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 {
@@ -262,37 +296,91 @@ trait Trees extends api.Trees { self: SymbolTable =>
case class ClassDef(mods: Modifiers, name: TypeName, tparams: List[TypeDef], impl: Template)
extends ImplDef with ClassDefApi
- object ClassDef extends ClassDefExtractor
+ object ClassDef extends ClassDefExtractor {
+ /** @param sym the class symbol
+ * @param impl the implementation template
+ * @return the class definition
+ */
+ def apply(sym: Symbol, impl: Template): ClassDef =
+ atPos(sym.pos) {
+ ClassDef(Modifiers(sym.flags),
+ sym.name.toTypeName,
+ sym.typeParams map TypeDef.apply,
+ impl) setSymbol sym
+ }
+
+ /** @param sym the class symbol
+ * @param body trees that constitute the body of the class
+ * @return the class definition
+ */
+ def apply(sym: Symbol, body: List[Tree]): ClassDef =
+ ClassDef(sym, Template(sym, body))
+ }
case class ModuleDef(mods: Modifiers, name: TermName, impl: Template)
extends ImplDef with ModuleDefApi
- object ModuleDef extends ModuleDefExtractor
+ object ModuleDef extends ModuleDefExtractor {
+ /**
+ * @param sym the class symbol
+ * @param impl the implementation template
+ */
+ def apply(sym: Symbol, impl: Template): ModuleDef =
+ atPos(sym.pos) {
+ ModuleDef(Modifiers(sym.flags), sym.name.toTermName, impl) setSymbol sym
+ }
+ }
abstract class ValOrDefDef extends MemberDef with ValOrDefDefApi {
- def name: Name
+ def name: TermName
def tpt: Tree
def rhs: Tree
}
+ object ValOrDefDef {
+ def unapply(tree: Tree): Option[(Modifiers, TermName, Tree, Tree)] = tree match {
+ case ValDef(mods, name, tpt, rhs) => Some((mods, name, tpt, rhs))
+ case DefDef(mods, name, _, _, tpt, rhs) => Some((mods, name, tpt, rhs))
+ case _ => None
+ }
+ }
+
case class ValDef(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree) extends ValOrDefDef with ValDefApi
- object ValDef extends ValDefExtractor
+ object ValDef extends ValDefExtractor {
+ def apply(sym: Symbol): ValDef = newValDef(sym, EmptyTree)()
+ def apply(sym: Symbol, rhs: Tree): ValDef = newValDef(sym, rhs)()
+ }
- case class DefDef(mods: Modifiers, name: Name, tparams: List[TypeDef],
+ case class DefDef(mods: Modifiers, name: TermName, tparams: List[TypeDef],
vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree) extends ValOrDefDef with DefDefApi
- object DefDef extends DefDefExtractor
+ object DefDef extends DefDefExtractor {
+ def apply(sym: Symbol, rhs: Tree): DefDef = newDefDef(sym, rhs)()
+ def apply(sym: Symbol, vparamss: List[List[ValDef]], rhs: Tree): DefDef = newDefDef(sym, rhs)(vparamss = vparamss)
+ def apply(sym: Symbol, mods: Modifiers, rhs: Tree): DefDef = newDefDef(sym, rhs)(mods = mods)
+ def apply(sym: Symbol, mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree): DefDef = newDefDef(sym, rhs)(mods = mods, vparamss = vparamss)
+ def apply(sym: Symbol, rhs: List[List[Symbol]] => Tree): DefDef = newDefDef(sym, rhs(sym.info.paramss))()
+ }
case class TypeDef(mods: Modifiers, name: TypeName, tparams: List[TypeDef], rhs: Tree)
extends MemberDef with TypeDefApi
- object TypeDef extends TypeDefExtractor
+ object TypeDef extends TypeDefExtractor {
+ /** A TypeDef node which defines abstract type or type parameter for given `sym` */
+ def apply(sym: Symbol): TypeDef = newTypeDef(sym, TypeBoundsTree(sym))()
+ def apply(sym: Symbol, rhs: Tree): TypeDef = newTypeDef(sym, rhs)()
+ }
case class LabelDef(name: TermName, params: List[Ident], rhs: Tree)
extends DefTree with TermTree with LabelDefApi
- object LabelDef extends LabelDefExtractor
+ object LabelDef extends LabelDefExtractor {
+ def apply(sym: Symbol, params: List[Symbol], rhs: Tree): LabelDef =
+ atPos(sym.pos) {
+ LabelDef(sym.name.toTermName, params map Ident, rhs) setSymbol sym
+ }
+ }
case class ImportSelector(name: Name, namePos: Int, rename: Name, renamePos: Int) extends ImportSelectorApi
object ImportSelector extends ImportSelectorExtractor {
val wild = ImportSelector(nme.WILDCARD, -1, null, -1)
- val wildList = List(wild)
+ val wildList = List(wild) // OPT This list is shared for performance.
}
case class Import(expr: Tree, selectors: List[ImportSelector])
@@ -416,6 +504,16 @@ trait Trees extends api.Trees { self: SymbolTable =>
def ApplyConstructor(tpt: Tree, args: List[Tree]) = Apply(Select(New(tpt), nme.CONSTRUCTOR), args)
+ // Creates a constructor call from the constructor symbol. This is
+ // to avoid winding up with an OverloadedType for the constructor call.
+ def NewFromConstructor(constructor: Symbol, args: Tree*) = {
+ assert(constructor.isConstructor, constructor)
+ val instance = New(TypeTree(constructor.owner.tpe))
+ val init = Select(instance, nme.CONSTRUCTOR) setSymbol constructor
+
+ Apply(init, args.toList)
+ }
+
case class ApplyDynamic(qual: Tree, args: List[Tree]) extends SymTree with TermTree
case class Super(qual: Tree, mix: TypeName) extends TermTree with SuperApi {
@@ -436,9 +534,9 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
object Select extends SelectExtractor
- case class Ident(name: Name) extends RefTree with IdentContextApi {
+ case class Ident(name: Name) extends RefTree with IdentApi {
def qualifier: Tree = EmptyTree
- def isBackquoted = this.attachments.get[BackquotedIdentifierAttachment.type].isDefined
+ def isBackquoted = this.hasAttachment[BackquotedIdentifierAttachment.type]
}
object Ident extends IdentExtractor
@@ -489,11 +587,11 @@ trait Trees extends api.Trees { self: SymbolTable =>
extends TypTree with TypeBoundsTreeApi
object TypeBoundsTree extends TypeBoundsTreeExtractor
- case class ExistentialTypeTree(tpt: Tree, whereClauses: List[Tree])
+ case class ExistentialTypeTree(tpt: Tree, whereClauses: List[MemberDef])
extends TypTree with ExistentialTypeTreeApi
object ExistentialTypeTree extends ExistentialTypeTreeExtractor
- case class TypeTree() extends TypTree with TypeTreeContextApi {
+ case class TypeTree() extends TypTree with TypeTreeApi {
private var orig: Tree = null
/** Was this type tree originally empty? That is, does it now contain
* an inferred type that must be forgotten in `resetAttrs` to
@@ -511,7 +609,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
case t => t
}
- orig = followOriginal(tree); setPos(tree.pos);
+ orig = followOriginal(tree); setPos(tree.pos)
this
}
@@ -536,8 +634,16 @@ trait Trees extends api.Trees { self: SymbolTable =>
object TypeTree extends TypeTreeExtractor
def TypeTree(tp: Type): TypeTree = TypeTree() setType tp
+ private def TypeTreeMemberType(sym: Symbol): TypeTree = {
+ // Needed for pos/t4970*.scala. See SI-7853
+ val resType = (if (sym.isLocalToBlock) sym.tpe else (sym.owner.thisType memberType sym)).finalResultType
+ atPos(sym.pos.focus)(TypeTree(resType))
+ }
- override type TreeCopier <: InternalTreeCopierOps
+ def TypeBoundsTree(bounds: TypeBounds): TypeBoundsTree = TypeBoundsTree(TypeTree(bounds.lo), TypeTree(bounds.hi))
+ def TypeBoundsTree(sym: Symbol): TypeBoundsTree = atPos(sym.pos)(TypeBoundsTree(sym.info.bounds))
+
+ override type TreeCopier >: Null <: InternalTreeCopierOps
abstract class InternalTreeCopierOps extends TreeCopierOps {
def ApplyDynamic(tree: Tree, qual: Tree, args: List[Tree]): ApplyDynamic
def ArrayValue(tree: Tree, elemtpt: Tree, trees: List[Tree]): ArrayValue
@@ -603,6 +709,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
case _: ApplyToImplicitArgs => new ApplyToImplicitArgs(fun, args)
case _: ApplyImplicitView => new ApplyImplicitView(fun, args)
// TODO: ApplyConstructor ???
+ case self.pendingSuperCall => self.pendingSuperCall
case _ => new Apply(fun, args)
}).copyAttrs(tree)
def ApplyDynamic(tree: Tree, qual: Tree, args: List[Tree]) =
@@ -615,6 +722,8 @@ trait Trees extends api.Trees { self: SymbolTable =>
new Select(qualifier, selector).copyAttrs(tree)
def Ident(tree: Tree, name: Name) =
new Ident(name) copyAttrs tree
+ def RefTree(tree: Tree, qualifier: Tree, selector: Name) =
+ self.RefTree(qualifier, selector) copyAttrs tree
def ReferenceToBoxed(tree: Tree, idt: Ident) =
new ReferenceToBoxed(idt).copyAttrs(tree)
def Literal(tree: Tree, value: Constant) =
@@ -633,7 +742,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
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]) =
+ def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[MemberDef]) =
new ExistentialTypeTree(tpt, whereClauses).copyAttrs(tree)
}
@@ -805,6 +914,11 @@ trait Trees extends api.Trees { self: SymbolTable =>
if name0 == name => t
case _ => treeCopy.Ident(tree, name)
}
+ def RefTree(tree: Tree, qualifier: Tree, selector: Name) = tree match {
+ case t @ Select(qualifier0, selector0)
+ if (qualifier0 == qualifier) && (selector0 == selector) => t
+ case _ => treeCopy.RefTree(tree, qualifier, selector)
+ }
def ReferenceToBoxed(tree: Tree, idt: Ident) = tree match {
case t @ ReferenceToBoxed(idt0)
if (idt0 == idt) => t
@@ -849,7 +963,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
if (lo0 == lo) && (hi0 == hi) => t
case _ => treeCopy.TypeBoundsTree(tree, lo, hi)
}
- def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[Tree]) = tree match {
+ def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[MemberDef]) = tree match {
case t @ ExistentialTypeTree(tpt0, whereClauses0)
if (tpt0 == tpt) && (whereClauses0 == whereClauses) => t
case _ => treeCopy.ExistentialTypeTree(tree, tpt, whereClauses)
@@ -866,7 +980,6 @@ trait Trees extends api.Trees { self: SymbolTable =>
/** 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 ---------------------------------------
@@ -912,6 +1025,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
if (flags1 == flags) this
else Modifiers(flags1, privateWithin, annotations) setPositions positions
}
+ def | (flag: Int): Modifiers = this | flag.toLong
def | (flag: Long): Modifiers = {
val flags1 = flags | flag
if (flags1 == flags) this
@@ -924,102 +1038,83 @@ trait Trees extends api.Trees { self: SymbolTable =>
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 mapAnnotations(f: List[Tree] => List[Tree]): Modifiers = {
+ val newAnns = f(annotations)
+ if (annotations == newAnns) this
+ else Modifiers(flags, privateWithin, newAnns) setPositions positions
+ }
override def toString = "Modifiers(%s, %s, %s)".format(flagString, annotations mkString ", ", positions)
}
- object Modifiers extends ModifiersCreator
+ object Modifiers extends ModifiersExtractor
implicit val ModifiersTag = ClassTag[Modifiers](classOf[Modifiers])
// ---- values and creators ---------------------------------------
- /** @param sym the class symbol
- * @return the implementation template
+ /** @param sym the template's symbol
+ * @param body trees that constitute the body of the template
+ * @return the template
*/
- def ClassDef(sym: Symbol, impl: Template): ClassDef =
+ def Template(sym: Symbol, body: List[Tree]): Template = {
atPos(sym.pos) {
- ClassDef(Modifiers(sym.flags),
- sym.name.toTypeName,
- sym.typeParams map TypeDef,
- impl) setSymbol sym
+ Template(sym.info.parents map TypeTree,
+ if (sym.thisSym == sym) noSelfType else ValDef(sym),
+ body)
}
-
- /**
- * @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)
-
- /** A DefDef with original trees attached to the TypeTree of each parameter */
- def DefDef(sym: Symbol, mods: Modifiers, originalParamTpts: Symbol => Tree, rhs: Tree): DefDef = {
- val paramms = mapParamss(sym){ sym =>
- val vd = ValDef(sym, EmptyTree)
- (vd.tpt : @unchecked) match {
- case tt: TypeTree => tt setOriginal (originalParamTpts(sym) setPos sym.pos.focus)
+ trait CannotHaveAttrs extends Tree {
+ super.setPos(NoPosition)
+ super.setType(NoType)
+
+ override def canHaveAttrs = false
+ override def setPos(pos: Position) = { requireLegal(pos, NoPosition, "pos"); this }
+ override def pos_=(pos: Position) = setPos(pos)
+ override def setType(t: Type) = { requireLegal(t, NoType, "tpe"); this }
+ override def tpe_=(t: Type) = setType(t)
+
+ private def requireLegal(value: Any, allowed: Any, what: String) = (
+ if (value != allowed) {
+ log(s"can't set $what for $self to value other than $allowed")
+ if (settings.debug && settings.developer)
+ (new Throwable).printStackTrace
}
- vd
- }
- DefDef(sym, mods, paramms, 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
- }
+ case object EmptyTree extends TermTree with CannotHaveAttrs { override def isEmpty = true; val asList = List(this) }
+ object noSelfType extends ValDef(Modifiers(PRIVATE), nme.WILDCARD, TypeTree(NoType), EmptyTree) with CannotHaveAttrs
+ object pendingSuperCall extends Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List()) with CannotHaveAttrs
+
+ @deprecated("Use `noSelfType` instead", "2.11.0") lazy val emptyValDef = noSelfType
+
+ def newValDef(sym: Symbol, rhs: Tree)(
+ mods: Modifiers = Modifiers(sym.flags),
+ name: TermName = sym.name.toTermName,
+ tpt: Tree = TypeTreeMemberType(sym)
+ ): ValDef = (
+ atPos(sym.pos)(ValDef(mods, name, tpt, rhs)) setSymbol sym
+ )
+
+ def newDefDef(sym: Symbol, rhs: Tree)(
+ mods: Modifiers = Modifiers(sym.flags),
+ name: TermName = sym.name.toTermName,
+ tparams: List[TypeDef] = sym.typeParams map TypeDef.apply,
+ vparamss: List[List[ValDef]] = mapParamss(sym)(ValDef.apply),
+ tpt: Tree = TypeTreeMemberType(sym)
+ ): DefDef = (
+ atPos(sym.pos)(DefDef(mods, name, tparams, vparamss, tpt, rhs)) setSymbol sym
+ )
+
+ def newTypeDef(sym: Symbol, rhs: Tree)(
+ mods: Modifiers = Modifiers(sym.flags),
+ name: TypeName = sym.name.toTypeName,
+ tparams: List[TypeDef] = sym.typeParams map TypeDef.apply
+ ): TypeDef = (
+ atPos(sym.pos)(TypeDef(mods, name, tparams, rhs)) setSymbol sym
+ )
/** casedef shorthand */
def CaseDef(pat: Tree, body: Tree): CaseDef =
@@ -1050,6 +1145,9 @@ trait Trees extends api.Trees { self: SymbolTable =>
def New(tpe: Type, args: Tree*): Tree =
ApplyConstructor(TypeTree(tpe), args.toList)
+ def New(tpe: Type, argss: List[List[Tree]]): Tree =
+ New(TypeTree(tpe), argss)
+
def New(sym: Symbol, args: Tree*): Tree =
New(sym.tpe, args: _*)
@@ -1094,113 +1192,136 @@ trait Trees extends api.Trees { self: SymbolTable =>
override protected def itraverse(traverser: Traverser, tree: Tree): Unit = {
import traverser._
- tree match {
- case EmptyTree =>
- ;
- case PackageDef(pid, stats) =>
- traverse(pid)
- atOwner(mclass(tree.symbol)) {
- traverseTrees(stats)
- }
- case ClassDef(mods, name, tparams, impl) =>
- atOwner(tree.symbol) {
- traverseTrees(mods.annotations); traverseTrees(tparams); traverse(impl)
- }
- case ModuleDef(mods, name, impl) =>
- atOwner(mclass(tree.symbol)) {
- traverseTrees(mods.annotations); traverse(impl)
- }
- case ValDef(mods, name, tpt, rhs) =>
- atOwner(tree.symbol) {
- traverseTrees(mods.annotations); traverse(tpt); traverse(rhs)
- }
- case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
- atOwner(tree.symbol) {
- traverseTrees(mods.annotations); traverseTrees(tparams); traverseTreess(vparamss); traverse(tpt); traverse(rhs)
- }
- case TypeDef(mods, name, tparams, rhs) =>
- atOwner(tree.symbol) {
- traverseTrees(mods.annotations); traverseTrees(tparams); traverse(rhs)
- }
+
+ def traverseMemberDef(md: MemberDef, owner: Symbol): Unit = atOwner(owner) {
+ traverseModifiers(md.mods)
+ traverseName(md.name)
+ md match {
+ case ClassDef(_, _, tparams, impl) => traverseParams(tparams) ; traverse(impl)
+ case ModuleDef(_, _, impl) => traverse(impl)
+ case ValDef(_, _, tpt, rhs) => traverseTypeAscription(tpt) ; traverse(rhs)
+ case TypeDef(_, _, tparams, rhs) => traverseParams(tparams) ; traverse(rhs)
+ case DefDef(_, _, tparams, vparamss, tpt, rhs) =>
+ traverseParams(tparams)
+ traverseParamss(vparamss)
+ traverseTypeAscription(tpt)
+ traverse(rhs)
+ }
+ }
+ def traverseComponents(): Unit = tree match {
case LabelDef(name, params, rhs) =>
- traverseTrees(params); traverse(rhs)
+ traverseName(name)
+ traverseParams(params)
+ traverse(rhs)
case Import(expr, selectors) =>
traverse(expr)
+ selectors foreach traverseImportSelector
case Annotated(annot, arg) =>
- traverse(annot); traverse(arg)
+ traverse(annot)
+ traverse(arg)
case Template(parents, self, body) =>
- traverseTrees(parents)
- if (!self.isEmpty) traverse(self)
+ traverseParents(parents)
+ traverseSelfType(self)
traverseStats(body, tree.symbol)
case Block(stats, expr) =>
- traverseTrees(stats); traverse(expr)
+ traverseTrees(stats)
+ traverse(expr)
case CaseDef(pat, guard, body) =>
- traverse(pat); traverse(guard); traverse(body)
+ traversePattern(pat)
+ traverseGuard(guard)
+ traverse(body)
case Alternative(trees) =>
traverseTrees(trees)
case Star(elem) =>
traverse(elem)
case Bind(name, body) =>
+ traverseName(name)
traverse(body)
case UnApply(fun, args) =>
- traverse(fun); traverseTrees(args)
+ traverse(fun)
+ traverseTrees(args)
case ArrayValue(elemtpt, trees) =>
- traverse(elemtpt); traverseTrees(trees)
- case Function(vparams, body) =>
- atOwner(tree.symbol) {
- traverseTrees(vparams); traverse(body)
- }
+ traverse(elemtpt)
+ traverseTrees(trees)
case Assign(lhs, rhs) =>
- traverse(lhs); traverse(rhs)
+ traverse(lhs)
+ traverse(rhs)
case AssignOrNamedArg(lhs, rhs) =>
- traverse(lhs); traverse(rhs)
+ traverse(lhs)
+ traverse(rhs)
case If(cond, thenp, elsep) =>
- traverse(cond); traverse(thenp); traverse(elsep)
+ traverse(cond)
+ traverse(thenp)
+ traverse(elsep)
case Match(selector, cases) =>
- traverse(selector); traverseTrees(cases)
+ traverse(selector)
+ traverseCases(cases)
case Return(expr) =>
traverse(expr)
case Try(block, catches, finalizer) =>
- traverse(block); traverseTrees(catches); traverse(finalizer)
+ traverse(block)
+ traverseCases(catches)
+ traverse(finalizer)
case Throw(expr) =>
traverse(expr)
case New(tpt) =>
traverse(tpt)
case Typed(expr, tpt) =>
- traverse(expr); traverse(tpt)
+ traverse(expr)
+ traverseTypeAscription(tpt)
case TypeApply(fun, args) =>
- traverse(fun); traverseTrees(args)
+ traverse(fun)
+ traverseTypeArgs(args)
case Apply(fun, args) =>
- traverse(fun); traverseTrees(args)
+ traverse(fun)
+ traverseTrees(args)
case ApplyDynamic(qual, args) =>
- traverse(qual); traverseTrees(args)
- case Super(qual, _) =>
traverse(qual)
- case This(_) =>
- ;
+ traverseTrees(args)
+ case Super(qual, mix) =>
+ traverse(qual)
+ traverseName(mix)
+ case This(qual) =>
+ traverseName(qual)
case Select(qualifier, selector) =>
traverse(qualifier)
- case Ident(_) =>
- ;
+ traverseName(selector)
+ case Ident(name) =>
+ traverseName(name)
case ReferenceToBoxed(idt) =>
traverse(idt)
- case Literal(_) =>
- ;
+ case Literal(const) =>
+ traverseConstant(const)
case TypeTree() =>
;
case SingletonTypeTree(ref) =>
traverse(ref)
case SelectFromTypeTree(qualifier, selector) =>
traverse(qualifier)
+ traverseName(selector)
case CompoundTypeTree(templ) =>
traverse(templ)
case AppliedTypeTree(tpt, args) =>
- traverse(tpt); traverseTrees(args)
+ traverse(tpt)
+ traverseTypeArgs(args)
case TypeBoundsTree(lo, hi) =>
- traverse(lo); traverse(hi)
+ traverse(lo)
+ traverse(hi)
case ExistentialTypeTree(tpt, whereClauses) =>
- traverse(tpt); traverseTrees(whereClauses)
- case _ => xtraverse(traverser, tree)
+ traverse(tpt)
+ traverseTrees(whereClauses)
+ case _ =>
+ xtraverse(traverser, tree)
+ }
+
+ if (tree.canHaveAttrs) {
+ tree match {
+ case PackageDef(pid, stats) => traverse(pid) ; traverseStats(stats, mclass(tree.symbol))
+ case md: ModuleDef => traverseMemberDef(md, mclass(tree.symbol))
+ case md: MemberDef => traverseMemberDef(md, tree.symbol)
+ case Function(vparams, body) => atOwner(tree.symbol) { traverseParams(vparams) ; traverse(body) }
+ case _ => traverseComponents()
+ }
}
}
@@ -1307,7 +1428,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
case CompoundTypeTree(templ) =>
treeCopy.CompoundTypeTree(tree, transformTemplate(templ))
case ExistentialTypeTree(tpt, whereClauses) =>
- treeCopy.ExistentialTypeTree(tree, transform(tpt), transformTrees(whereClauses))
+ treeCopy.ExistentialTypeTree(tree, transform(tpt), transformMemberDefs(whereClauses))
case Return(expr) =>
treeCopy.Return(tree, transform(expr))
case Alternative(trees) =>
@@ -1315,7 +1436,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
case Star(elem) =>
treeCopy.Star(tree, transform(elem))
case UnApply(fun, args) =>
- treeCopy.UnApply(tree, fun, transformTrees(args)) // bq: see test/.../unapplyContexts2.scala
+ treeCopy.UnApply(tree, transform(fun), transformTrees(args)) // bq: see test/.../unapplyContexts2.scala
case ArrayValue(elemtpt, trees) =>
treeCopy.ArrayValue(tree, transform(elemtpt), transformTrees(trees))
case ApplyDynamic(qual, args) =>
@@ -1331,9 +1452,6 @@ trait Trees extends api.Trees { self: SymbolTable =>
// --- specific traversers and transformers
- @deprecated("Moved to tree.duplicate", "2.10.0")
- protected[scala] def duplicateTree(tree: Tree): Tree = tree.duplicate
-
class ForeachPartialTreeTraverser(pf: PartialFunction[Tree, Tree]) extends Traverser {
override def traverse(tree: Tree) {
val t = if (pf isDefinedAt tree) pf(tree) else tree
@@ -1372,6 +1490,16 @@ trait Trees extends api.Trees { self: SymbolTable =>
if (tree eq orig) super.transform(tree)
else tree
}
+
+ /** A transformer that replaces tree `from` with tree `to` in a given tree */
+ class TreeReplacer(from: Tree, to: Tree, positionAware: Boolean) extends Transformer {
+ override def transform(t: Tree): Tree = {
+ if (t == from) to
+ else if (!positionAware || (t.pos includes from.pos) || t.pos.isTransparent) super.transform(t)
+ else t
+ }
+ }
+
// 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 ", ")
@@ -1387,7 +1515,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
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);
+ else subst(from.tail, to.tail)
subst(from, to)
case _ =>
super.transform(tree)
@@ -1400,7 +1528,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
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 modifyType (_.substThis(clazz, newtpe))
tree match {
case This(_) if tree.symbol == clazz => to
case _ => super.transform(tree)
@@ -1410,8 +1538,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
class TypeMapTreeSubstituter(val typeMap: TypeMap) extends Traverser {
override def traverse(tree: Tree) {
- if (tree.tpe ne null)
- tree.tpe = typeMap(tree.tpe)
+ tree modifyType typeMap
if (tree.isDef)
tree.symbol modifyInfo typeMap
@@ -1448,9 +1575,9 @@ trait Trees extends api.Trees { self: SymbolTable =>
if (tree.symbol == from.head) tree setSymbol to.head
else subst(from.tail, to.tail)
}
+ tree modifyType symSubst
- if (tree.tpe ne null) tree.tpe = symSubst(tree.tpe)
- if (tree.hasSymbol) {
+ if (tree.hasSymbolField) {
subst(from, to)
tree match {
case _: DefTree =>
@@ -1492,7 +1619,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
class FilterTreeTraverser(p: Tree => Boolean) extends Traverser {
- val hits = new ListBuffer[Tree]
+ val hits = mutable.ListBuffer[Tree]()
override def traverse(t: Tree) {
if (p(t)) hits += t
super.traverse(t)
@@ -1500,7 +1627,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
class CollectTreeTraverser[T](pf: PartialFunction[Tree, T]) extends Traverser {
- val results = new ListBuffer[T]
+ val results = mutable.ListBuffer[T]()
override def traverse(t: Tree) {
if (pf.isDefinedAt(t)) results += pf(t)
super.traverse(t)
@@ -1517,6 +1644,15 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
}
+ private lazy val duplicator = new Duplicator(focusPositions = true)
+ private class Duplicator(focusPositions: Boolean) extends Transformer {
+ override val treeCopy = newStrictTreeCopier
+ override def transform(t: Tree) = {
+ val t1 = super.transform(t)
+ if ((t1 ne t) && t1.pos.isRange && focusPositions) t1 setPos t.pos.focus
+ t1
+ }
+ }
trait TreeStackTraverser extends Traverser {
import collection.mutable
val path: mutable.Stack[Tree] = mutable.Stack()
@@ -1526,27 +1662,32 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
}
- private lazy val duplicator = new Duplicator(focusPositions = true)
- private class Duplicator(focusPositions: Boolean) extends Transformer {
- override val treeCopy = newStrictTreeCopier
- override def transform(t: Tree) = {
- val t1 = super.transform(t)
- if ((t1 ne t) && t1.pos.isRange && focusPositions) t1 setPos t.pos.focus
- t1
+ /** Tracks the classes currently under construction during a transform */
+ trait UnderConstructionTransformer extends Transformer {
+ import collection.mutable
+
+ protected def isUnderConstruction(clazz: Symbol) = selfOrSuperCalls contains clazz
+
+ /** The stack of class symbols in which a call to this() or to the super
+ * constructor, or early definition is active */
+ private val selfOrSuperCalls = mutable.Stack[Symbol]()
+
+ abstract override def transform(tree: Tree) = {
+ if ((treeInfo isSelfOrSuperConstrCall tree) || (treeInfo isEarlyDef tree)) {
+ selfOrSuperCalls push currentOwner.owner
+ try super.transform(tree)
+ finally selfOrSuperCalls.pop()
+ } else super.transform(tree)
}
}
def duplicateAndKeepPositions(tree: Tree) = new Duplicator(focusPositions = false) transform tree
- def wrapIntoTerm(tree: Tree): Tree = {
- if (!tree.isTerm) Block(List(tree), Literal(Constant(()))) else tree
- }
-
// this is necessary to avoid crashes like https://github.com/scalamacros/paradise/issues/1
// when someone tries to c.typecheck a naked MemberDef
def wrappingIntoTerm(tree0: Tree)(op: Tree => Tree): Tree = {
val neededWrapping = !tree0.isTerm
- val tree1 = wrapIntoTerm(tree0)
+ val tree1 = build.SyntacticBlock(tree0 :: Nil)
op(tree1) match {
case Block(tree2 :: Nil, Literal(Constant(()))) if neededWrapping => tree2
case tree2 => tree2
@@ -1591,6 +1732,22 @@ trait Trees extends api.Trees { self: SymbolTable =>
case t =>
sys.error("Not a ValDef: " + t + "/" + t.getClass)
}
+ def copyTypeDef(tree: Tree)(
+ mods: Modifiers = null,
+ name: Name = null,
+ tparams: List[TypeDef] = null,
+ rhs: Tree = null
+ ): TypeDef = tree match {
+ case TypeDef(mods0, name0, tparams0, rhs0) =>
+ treeCopy.TypeDef(tree,
+ if (mods eq null) mods0 else mods,
+ if (name eq null) name0 else name,
+ if (tparams eq null) tparams0 else tparams,
+ if (rhs eq null) rhs0 else rhs
+ )
+ case t =>
+ sys.error("Not a TypeDef: " + t + "/" + t.getClass)
+ }
def copyClassDef(tree: Tree)(
mods: Modifiers = null,
name: Name = null,
@@ -1608,6 +1765,21 @@ trait Trees extends api.Trees { self: SymbolTable =>
sys.error("Not a ClassDef: " + t + "/" + t.getClass)
}
+ def copyModuleDef(tree: Tree)(
+ mods: Modifiers = null,
+ name: Name = null,
+ impl: Template = null
+ ): ModuleDef = tree match {
+ case ModuleDef(mods0, name0, impl0) =>
+ treeCopy.ModuleDef(tree,
+ if (mods eq null) mods0 else mods,
+ if (name eq null) name0 else name,
+ if (impl eq null) impl0 else impl
+ )
+ case t =>
+ sys.error("Not a ModuleDef: " + 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))
@@ -1650,62 +1822,68 @@ trait Trees extends api.Trees { self: SymbolTable =>
case t =>
sys.error("Not a LabelDef: " + t + "/" + t.getClass)
}
+ def deriveFunction(func: Tree)(applyToRhs: Tree => Tree): Function = func match {
+ case Function(params0, rhs0) =>
+ treeCopy.Function(func, params0, applyToRhs(rhs0))
+ case t =>
+ sys.error("Not a Function: " + t + "/" + t.getClass)
+ }
// -------------- Classtags --------------------------------------------------------
- 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 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 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 AlternativeTag = ClassTag[Alternative](classOf[Alternative])
+ implicit val AnnotatedTag = ClassTag[Annotated](classOf[Annotated])
+ implicit val AppliedTypeTreeTag = ClassTag[AppliedTypeTree](classOf[AppliedTypeTree])
+ implicit val ApplyTag = ClassTag[Apply](classOf[Apply])
+ implicit val AssignOrNamedArgTag = ClassTag[AssignOrNamedArg](classOf[AssignOrNamedArg])
+ implicit val AssignTag = ClassTag[Assign](classOf[Assign])
+ implicit val BindTag = ClassTag[Bind](classOf[Bind])
+ implicit val BlockTag = ClassTag[Block](classOf[Block])
+ implicit val CaseDefTag = ClassTag[CaseDef](classOf[CaseDef])
+ implicit val ClassDefTag = ClassTag[ClassDef](classOf[ClassDef])
+ implicit val CompoundTypeTreeTag = ClassTag[CompoundTypeTree](classOf[CompoundTypeTree])
+ implicit val DefDefTag = ClassTag[DefDef](classOf[DefDef])
+ implicit val DefTreeTag = ClassTag[DefTree](classOf[DefTree])
implicit val ExistentialTypeTreeTag = ClassTag[ExistentialTypeTree](classOf[ExistentialTypeTree])
- implicit val TypeTreeTag = ClassTag[TypeTree](classOf[TypeTree])
+ implicit val FunctionTag = ClassTag[Function](classOf[Function])
+ implicit val GenericApplyTag = ClassTag[GenericApply](classOf[GenericApply])
+ implicit val IdentTag = ClassTag[Ident](classOf[Ident])
+ implicit val IfTag = ClassTag[If](classOf[If])
+ implicit val ImplDefTag = ClassTag[ImplDef](classOf[ImplDef])
+ implicit val ImportSelectorTag = ClassTag[ImportSelector](classOf[ImportSelector])
+ implicit val ImportTag = ClassTag[Import](classOf[Import])
+ implicit val LabelDefTag = ClassTag[LabelDef](classOf[LabelDef])
+ implicit val LiteralTag = ClassTag[Literal](classOf[Literal])
+ implicit val MatchTag = ClassTag[Match](classOf[Match])
+ implicit val MemberDefTag = ClassTag[MemberDef](classOf[MemberDef])
+ implicit val ModuleDefTag = ClassTag[ModuleDef](classOf[ModuleDef])
+ implicit val NameTreeTag = ClassTag[NameTree](classOf[NameTree])
+ implicit val NewTag = ClassTag[New](classOf[New])
+ implicit val PackageDefTag = ClassTag[PackageDef](classOf[PackageDef])
+ implicit val ReferenceToBoxedTag = ClassTag[ReferenceToBoxed](classOf[ReferenceToBoxed])
+ implicit val RefTreeTag = ClassTag[RefTree](classOf[RefTree])
+ implicit val ReturnTag = ClassTag[Return](classOf[Return])
+ implicit val SelectFromTypeTreeTag = ClassTag[SelectFromTypeTree](classOf[SelectFromTypeTree])
+ implicit val SelectTag = ClassTag[Select](classOf[Select])
+ implicit val SingletonTypeTreeTag = ClassTag[SingletonTypeTree](classOf[SingletonTypeTree])
+ implicit val StarTag = ClassTag[Star](classOf[Star])
+ implicit val SuperTag = ClassTag[Super](classOf[Super])
+ implicit val SymTreeTag = ClassTag[SymTree](classOf[SymTree])
+ implicit val TemplateTag = ClassTag[Template](classOf[Template])
+ implicit val TermTreeTag = ClassTag[TermTree](classOf[TermTree])
+ implicit val ThisTag = ClassTag[This](classOf[This])
+ implicit val ThrowTag = ClassTag[Throw](classOf[Throw])
+ implicit val TreeTag = ClassTag[Tree](classOf[Tree])
+ implicit val TryTag = ClassTag[Try](classOf[Try])
+ implicit val TypTreeTag = ClassTag[TypTree](classOf[TypTree])
+ implicit val TypeApplyTag = ClassTag[TypeApply](classOf[TypeApply])
+ implicit val TypeBoundsTreeTag = ClassTag[TypeBoundsTree](classOf[TypeBoundsTree])
+ implicit val TypeDefTag = ClassTag[TypeDef](classOf[TypeDef])
+ implicit val TypeTreeTag = ClassTag[TypeTree](classOf[TypeTree])
+ implicit val TypedTag = ClassTag[Typed](classOf[Typed])
+ implicit val UnApplyTag = ClassTag[UnApply](classOf[UnApply])
+ implicit val ValDefTag = ClassTag[ValDef](classOf[ValDef])
+ implicit val ValOrDefDefTag = ClassTag[ValOrDefDef](classOf[ValOrDefDef])
val treeNodeCount = Statistics.newView("#created tree nodes")(nodeCount)
}
diff --git a/src/reflect/scala/reflect/internal/TypeDebugging.scala b/src/reflect/scala/reflect/internal/TypeDebugging.scala
index 68b4fa69a1..63f897cd32 100644
--- a/src/reflect/scala/reflect/internal/TypeDebugging.scala
+++ b/src/reflect/scala/reflect/internal/TypeDebugging.scala
@@ -3,16 +3,77 @@
* @author Paul Phillips
*/
-package scala.reflect
+package scala
+package reflect
package internal
+import util._
+
trait TypeDebugging {
self: SymbolTable =>
import definitions._
- // @M toString that is safe during debugging (does not normalize, ...)
+ /** There's a whole lot of implementation detail which is nothing but noise when
+ * you are trying to see what's going on. This is my attempt to filter it out.
+ */
+ object noPrint extends (Tree => Boolean) {
+ def skipScalaName(name: Name) = name match {
+ case tpnme.Any | tpnme.Nothing | tpnme.AnyRef => true
+ case _ => false
+ }
+ def skipRefTree(t: RefTree) = t match {
+ case Select(Select(Ident(nme.ROOTPKG), nme.scala_), name) if skipScalaName(name) => true
+ case Select(sel, name) if sel.symbol == ScalaPackage && skipScalaName(name) => true
+ case Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR) => true
+ case Ident(nme.ROOTPKG) => true
+ case _ => skipSym(t.symbol)
+ }
+ def skipSym(sym: Symbol): Boolean = sym match {
+ case null => false
+ case NothingClass | AnyClass => true
+ case PredefModule => true
+ case ObjectClass => true
+ case _ => sym.hasPackageFlag
+ }
+ def skipType(tpe: Type): Boolean = (tpe eq null) || skipSym(tpe.typeSymbolDirect)
+
+ def skip(t: Tree): Boolean = t match {
+ case EmptyTree => true
+ case PackageDef(_, _) => true
+ case t: RefTree => skipRefTree(t)
+ case TypeBoundsTree(lo, hi) => skip(lo) && skip(hi)
+ case Block(Nil, expr) => skip(expr)
+ case Apply(fn, Nil) => skip(fn)
+ case Block(stmt :: Nil, expr) => skip(stmt) && skip(expr)
+ case DefDef(_, nme.CONSTRUCTOR, Nil, ListOfNil, _, rhs) => skip(rhs)
+ case Literal(Constant(())) => true
+ case tt @ TypeTree() => skipType(tt.tpe)
+ case _ => skipSym(t.symbol)
+ }
+ def apply(t: Tree) = skip(t)
+ }
+
+ /** Light color wrappers.
+ */
object typeDebug {
+ import scala.Console._
+
+ private val colorsOk = sys.props contains "scala.color"
+ private def inColor(s: String, color: String) = if (colorsOk && s != "") color + s + RESET else s
+ private def inBold(s: String, color: String) = if (colorsOk && s != "") color + BOLD + s + RESET else s
+
+ def inLightRed(s: String) = inColor(s, RED)
+ def inLightGreen(s: String) = inColor(s, GREEN)
+ def inLightMagenta(s: String) = inColor(s, MAGENTA)
+ def inLightCyan(s: String): String = inColor(s, CYAN)
+ def inGreen(s: String): String = inBold(s, GREEN)
+ def inRed(s: String): String = inBold(s, RED)
+ def inBlue(s: String): String = inBold(s, BLUE)
+ def inCyan(s: String): String = inBold(s, CYAN)
+ def inMagenta(s: String) = inBold(s, MAGENTA)
+ def resetColor(s: String): String = if (colorsOk) s + RESET else s
+
private def to_s(x: Any): String = x match {
// otherwise case classes are caught looking like products
case _: Tree | _: Type => "" + x
@@ -20,7 +81,6 @@ trait TypeDebugging {
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 {
@@ -31,16 +91,32 @@ trait TypeDebugging {
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 ptLine(pairs: (String, Any)*): String = (
+ pairs
+ map { case (k, v) => (k, to_s(v)) }
+ filterNot { case (_, v) => v == "" }
+ map { case ("", v) => v ; case (k, v) => s"$k=$v" }
+ mkString ", "
+ )
+ def ptTree(t: Tree): String = t match {
+ case PackageDef(pid, _) => s"package $pid"
+ case ModuleDef(_, name, _) => s"object $name"
+ case DefDef(_, name, tparams, _, _, _) => "def " + name + ptTypeParams(tparams)
+ case ClassDef(_, name, Nil, _) if t.symbol != null && t.symbol.isModuleClass => s"module class $name"
+ case ClassDef(_, name, tparams, _) => "class " + name + ptTypeParams(tparams)
+ case td: TypeDef => ptTypeParam(td)
+ case TypeBoundsTree(lo, hi) =>
+ val lo_s = if (noPrint(lo)) "" else " >: " + ptTree(lo)
+ val hi_s = if (noPrint(hi)) "" else " <: " + ptTree(hi)
+ lo_s + hi_s
+ case _ if (t.symbol eq null) || (t.symbol eq NoSymbol) => to_s(t)
+ case _ => "" + t.symbol.tpe
}
- 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)
+ def ptTypeParam(td: TypeDef): String = {
+ val TypeDef(_, name, tparams, rhs) = td
+ name + ptTypeParams(tparams) + ptTree(rhs)
}
+ def ptTypeParams(tparams: List[TypeDef]): String = str brackets (tparams map ptTypeParam)
object str {
def parentheses(xs: List[_]): String = xs.mkString("(", ", ", ")")
@@ -48,24 +124,28 @@ trait TypeDebugging {
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 ", "}")
+ def bounds(lo: Type, hi: Type): String = {
+ val lo_s = if (typeIsNothing(lo)) "" else s" >: $lo"
+ val hi_s = if (typeIsAny(hi)) "" else s" <: $hi"
+ lo_s + hi_s
+ }
}
-
+ import str._
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...
+ case TypeRef(pre, sym, args) => s"${debug(pre)}.${sym.nameString}.${tparams(args)}"
+ case ThisType(sym) => s"${sym.nameString}.this"
+ case SingleType(pre, sym) => s"${debug(pre)}.${sym.nameString}.type"
+ case RefinedType(ps, decls) => s"${parents(ps)} ${refine(decls)}"
+ case ClassInfoType(ps, decls, clazz) => s"class ${clazz.nameString} ${parents(ps)} ${refine(decls)}"
+ case PolyType(tparams, result) => s"${brackets(tparams)}${debug(result)}"
+ case TypeBounds(lo, hi) => bounds(lo, hi)
+ case tv @ TypeVar(_, _) => "" + tv
+ case ExistentialType(tparams, qtpe) => s"forSome ${brackets(tparams)} ${debug(qtpe)}"
+ case _ => s"?${shortClassOfInstance(tp)}?" // 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
index 2f49995030..f26315c538 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -3,19 +3,21 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package 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 scala.runtime.ObjectRef
import util.ThreeValues._
+import Variance._
+import Depth._
+import TypeConstants._
/* A standard type pattern match:
case ErrorType =>
@@ -41,7 +43,7 @@ import util.ThreeValues._
// parent1 with ... with parentn { defs }
case ExistentialType(tparams, result) =>
// result forSome { tparams }
- case AnnotatedType(annots, tp, selfsym) =>
+ case AnnotatedType(annots, tp) =>
// tp @annots
// the following are non-value types; you cannot write them down in Scala source.
@@ -68,147 +70,63 @@ import util.ThreeValues._
// 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, args)
- // for dependent method types: a type referring to a method parameter.
- case ErasedValueType(tref)
+ case ErasedValueType(clazz, underlying)
// only used during erasure of derived value classes.
*/
-trait Types extends api.Types { self: SymbolTable =>
+trait Types
+ extends api.Types
+ with tpe.TypeComparers
+ with tpe.TypeToStrings
+ with tpe.CommonOwners
+ with tpe.GlbLubs
+ with tpe.TypeMaps
+ with tpe.TypeConstraints
+ with tpe.FindMembers
+ with util.Collections { self: SymbolTable =>
+
import definitions._
import TypesStats._
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
+ private final val breakCycles = settings.breakCycles.value
+ /** In case anyone wants to turn on type parameter bounds being used
* to seed type constraints.
*/
private final val propagateParameterBoundsToTypeVars = sys.props contains "scalac.debug.prop-constraints"
+ private final val sharperSkolems = sys.props contains "scalac.experimental.sharper-skolems"
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]()
+ /** Caching the most recent map has a 75-90% hit rate. */
+ private object substTypeMapCache {
+ private[this] var cached: SubstTypeMap = new SubstTypeMap(Nil, Nil)
- /** 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
+ def apply(from: List[Symbol], to: List[Type]): SubstTypeMap = {
+ if ((cached.from ne from) || (cached.to ne to))
+ cached = new SubstTypeMap(from, to)
- protected def newUndoLog = new UndoLog
-
- class UndoLog extends Clearable {
- private type UndoPairs = List[(TypeVar, TypeConstraint)]
- //OPT this method is public so we can do `manual inlining`
- var log: UndoPairs = List()
-
- /*
- * These two methods provide explicit locking mechanism that is overridden in SynchronizedUndoLog.
- *
- * The idea behind explicit locking mechanism is that all public methods that access mutable state
- * will have to obtain the lock for their entire execution so both reads and writes can be kept in
- * right order. Originally, that was achieved by overriding those public methods in
- * `SynchronizedUndoLog` which was fine but expensive. The reason is that those public methods take
- * thunk as argument and if we keep them non-final there's no way to make them inlined so thunks
- * can go away.
- *
- * By using explicit locking we can achieve inlining.
- *
- * NOTE: They are made public for now so we can apply 'manual inlining' (copy&pasting into hot
- * places implementation of `undo` or `undoUnless`). This should be changed back to protected
- * once inliner is fixed.
- */
- def lock(): Unit = ()
- def unlock(): Unit = ()
-
- // register with the auto-clearing cache manager
- perRunCaches.recordCache(this)
-
- /** Undo all changes to constraints to type variables upto `limit`. */
- //OPT this method is public so we can do `manual inlining`
- def undoTo(limit: UndoPairs) {
- assertCorrectThread()
- 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() {
- lock()
- try {
- if (settings.debug.value)
- self.log("Clearing " + log.size + " entries from the undoLog.")
- log = Nil
- } finally unlock()
- }
- def size = {
- lock()
- try log.size finally unlock()
- }
-
- // `block` should not affect constraints on typevars
- def undo[T](block: => T): T = {
- lock()
- try {
- val before = log
-
- try block
- finally undoTo(before)
- } finally unlock()
- }
-
- // if `block` evaluates to false, it should not affect constraints on typevars
- def undoUnless(block: => Boolean): Boolean = {
- lock()
- try {
- val before = log
- var result = false
-
- try result = block
- finally if (!result) undoTo(before)
-
- result
- } finally unlock()
+ cached
}
}
+ /** The current skolemization level, needed for the algorithms
+ * in isSameType, isSubType that do constraint solving under a prefix.
+ */
+ private var _skolemizationLevel = 0
+ def skolemizationLevel = _skolemizationLevel
+ def skolemizationLevel_=(value: Int) = _skolemizationLevel = value
+
/** A map from lists to compound types that have the given list as parents.
* This is used to avoid duplication in the computation of base type sequences and baseClasses.
* It makes use of the fact that these two operations depend only on the parents,
* not on the refinement.
*/
- val intersectionWitness = perRunCaches.newWeakMap[List[Type], WeakReference[Type]]()
+ private val _intersectionWitness = perRunCaches.newWeakMap[List[Type], WeakReference[Type]]()
+ def intersectionWitness = _intersectionWitness
/** A proxy for a type (identified by field `underlying`) that forwards most
* operations to it (for exceptions, see WrappingProxy, which forwards even more operations).
@@ -223,12 +141,8 @@ trait Types extends api.Types { self: SymbolTable =>
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
@@ -256,7 +170,14 @@ trait Types extends api.Types { self: SymbolTable =>
* 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 maybeRewrap(newtp: Type) = (
+ if (newtp eq underlying) this
+ // BoundedWildcardTypes reach here during erroneous compilation: neg/t6258
+ // Higher-kinded exclusion is because [x]CC[x] compares =:= to CC: pos/t3800
+ // Otherwise, if newtp =:= underlying, don't rewrap it.
+ else if (!newtp.isWildcard && !newtp.isHigherKinded && (newtp =:= 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
@@ -266,16 +187,15 @@ trait Types extends api.Types { self: SymbolTable =>
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 etaExpand = maybeRewrap(underlying.etaExpand)
override def dealias = maybeRewrap(underlying.dealias)
override def cloneInfo(owner: Symbol) = maybeRewrap(underlying.cloneInfo(owner))
override def atOwner(owner: Symbol) = maybeRewrap(underlying.atOwner(owner))
@@ -297,7 +217,6 @@ trait Types extends api.Types { self: SymbolTable =>
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 {
@@ -325,18 +244,16 @@ trait Types extends api.Types { self: SymbolTable =>
def isSpliceable = {
this.isInstanceOf[TypeRef] && typeSymbol.isAbstractType && !typeSymbol.isExistential
}
- }
- /** Same as a call to narrow unless existentials are visible
- * after widening the type. In that case, narrow from the widened
- * type instead of the proxy. This gives buried existentials a
- * chance to make peace with the other types. See SI-5330.
- */
- private def narrowForFindMember(tp: Type): Type = {
- val w = tp.widen
- // Only narrow on widened type when we have to -- narrow is expensive unless the target is a singleton type.
- if ((tp ne w) && containsExistential(w)) w.narrow
- else tp.narrow
+ def companion = {
+ val sym = typeSymbolDirect
+ if (sym.isModule && !sym.isPackage) sym.companionSymbol.tpe
+ else if (sym.isModuleClass && !sym.isPackageClass) sym.sourceModule.companionSymbol.tpe
+ else if (sym.isClass && !sym.isModuleClass && !sym.isPackageClass) sym.companionSymbol.info
+ else NoType
+ }
+
+ def paramLists: List[List[Symbol]] = paramss
}
/** The base class for all types */
@@ -351,7 +268,7 @@ trait Types extends api.Types { self: SymbolTable =>
def takesTypeArgs: Boolean = this.isHigherKinded
/** Does this type denote a stable reference (i.e. singleton type)? */
- def isStable: Boolean = false
+ final def isStable: Boolean = definitions isStable this
/** Is this type dangerous (i.e. it might contain conflicting
* type information when empty, so that it can be constructed
@@ -359,10 +276,7 @@ trait Types extends api.Types { self: SymbolTable =>
* 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
+ final def isVolatile: Boolean = definitions isVolatile this
/** Is this type a structural refinement type (it ''refines'' members that have not been inherited) */
def isStructuralRefinement: Boolean = false
@@ -384,15 +298,11 @@ trait Types extends api.Types { self: SymbolTable =>
/** 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: Boolean =
- typeSymbol.isFinal && (typeSymbol.typeParams forall symbolIsNonVariant) && prefix.isStable
+ def isFinalType = typeSymbol.hasOnlyBottomSubclasses && prefix.isStable
/** Is this type completed (i.e. not a lazy type)? */
def isComplete: Boolean = true
@@ -489,7 +399,7 @@ trait Types extends api.Types { self: SymbolTable =>
/** 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
+ def firstParent = if (parents.nonEmpty) parents.head else ObjectTpe
/** For a typeref or single-type, the prefix of the normalized type (@see normalize).
* NoType for all other types. */
@@ -524,14 +434,9 @@ trait Types extends api.Types { self: SymbolTable =>
/** 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
+ final def finalResultType: Type = definitions finalResultType this
/** For a method type, the number of its value parameter sections,
* 0 for all other types */
@@ -557,13 +462,6 @@ trait Types extends api.Types { self: SymbolTable =>
* 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
@@ -589,15 +487,39 @@ trait Types extends api.Types { self: SymbolTable =>
* 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)))
+ *
+ * Discussion: normalize is NOT usually what you want to be calling.
+ * The (very real) danger with normalize is that it will force types
+ * which would not otherwise have been forced, leading to mysterious
+ * behavioral differences, cycles, and other elements of mysteries.
+ * Under most conditions the method you should be calling is `dealiasWiden`
+ * (see that method for more info.)
+ *
+ * Here are a few of the side-effect-trail-leaving methods called
+ * by various implementations of normalize:
+ *
+ * - sym.info
+ * - tpe.etaExpand
+ * - tpe.betaReduce
+ * - tpe.memberType
+ * - sym.nextOverriddenSymbol
+ * - constraint.inst
+ *
+ * If you've been around the compiler a while that list must fill
+ * your heart with fear.
*/
def normalize = this // @MAT
+ def etaExpand = this
+
/** Expands type aliases. */
def dealias = this
/** Repeatedly apply widen and dealias until they have no effect.
* This compensates for the fact that type aliases can hide beneath
* singleton types and singleton types can hide inside type aliases.
+ * !!! - and yet it is still inadequate, because aliases and singletons
+ * might lurk in the upper bounds of an abstract type. See SI-7051.
*/
def dealiasWiden: Type = (
if (this ne widen) widen.dealiasWiden
@@ -615,8 +537,6 @@ trait Types extends api.Types { self: SymbolTable =>
else Nil
)
- def etaExpand: Type = this
-
/** Performs a single step of beta-reduction on types.
* Given:
*
@@ -686,16 +606,6 @@ trait Types extends api.Types { self: SymbolTable =>
def nonPrivateMember(name: Name): Symbol =
memberBasedOnName(name, BridgeAndPrivateFlags)
- /** All members with the given flags, excluding bridges.
- */
- def membersWithFlags(requiredFlags: Long): Scope =
- membersBasedOnFlags(BridgeFlags, requiredFlags)
-
- /** All non-private members with the given flags, excluding bridges.
- */
- def nonPrivateMembersWithFlags(requiredFlags: Long): Scope =
- 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
@@ -716,10 +626,9 @@ trait Types extends api.Types { self: SymbolTable =>
*/
def membersBasedOnFlags(excludedFlags: Long, requiredFlags: Long): Scope =
findMembers(excludedFlags, requiredFlags)
-// findMember(nme.ANYNAME, excludedFlags, requiredFlags, false).alternatives
def memberBasedOnName(name: Name, excludedFlags: Long): Symbol =
- findMember(name, excludedFlags, 0, false)
+ findMember(name, excludedFlags, 0, stableOnly = false)
/** The least type instance of given class which is a supertype
* of this type. Example:
@@ -750,7 +659,7 @@ trait Types extends api.Types { self: SymbolTable =>
)
if (trivial) this
else {
- val m = new AsSeenFromMap(pre.normalize, clazz)
+ val m = newAsSeenFromMap(pre.normalize, clazz)
val tp = m(this)
val tp1 = existentialAbstraction(m.capturedParams, tp)
@@ -770,6 +679,7 @@ trait Types extends api.Types { self: SymbolTable =>
* }}}
*/
def memberInfo(sym: Symbol): Type = {
+ require(sym ne NoSymbol, this)
sym.info.asSeenFrom(this, sym.owner)
}
@@ -785,15 +695,14 @@ trait Types extends api.Types { self: SymbolTable =>
case OverloadedType(_, alts) =>
OverloadedType(this, alts)
case tp =>
- tp.asSeenFrom(this, sym.owner)
+ if (sym eq NoSymbol) NoType else 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
+ if (from.isEmpty) this else substTypeMapCache(from, to)(this)
/** Substitute symbols `to` for occurrences of symbols `from` in this type.
*
@@ -830,7 +739,6 @@ trait Types extends api.Types { self: SymbolTable =>
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){
@@ -838,6 +746,8 @@ trait Types extends api.Types { self: SymbolTable =>
def map[T](f: Type => T): List[T] = collect(Type.this) map f
}
+ @inline final def orElse(alt: => Type): Type = if (this ne NoType) this else alt
+
/** Returns optionally first type (in a preorder traversal) which satisfies predicate `p`,
* or None if none exists.
*/
@@ -860,45 +770,46 @@ trait Types extends api.Types { self: SymbolTable =>
/** 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 (Statistics.canEnable) stat_<:<(that)
else {
(this eq that) ||
- (if (explainSwitch) explain("<:", isSubType, this, that)
- else isSubType(this, that, AnyDepth))
+ (if (explainSwitch) explain("<:", isSubType(_: Type, _: Type), this, that)
+ else isSubType(this, that))
}
}
/** Is this type a subtype of that type in a pattern context?
- * Any type arguments on the right hand side are replaced with
+ * Dummy 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 matchesPattern(that: Type): Boolean = (this <:< that) || (that match {
+ case ArrayTypeRef(elem2) if elem2.typeConstructor.isHigherKinded =>
+ this match {
+ case ArrayTypeRef(elem1) => elem1 matchesPattern elem2
+ case _ => false
+ }
+ case TypeRef(_, sym, args) =>
+ val that1 = existentialAbstraction(args map (_.typeSymbol), that)
+ (that ne that1) && (this <:< that1) && {
+ debuglog(s"$this.matchesPattern($that) depended on discarding args and testing <:< $that1")
+ true
+ }
+ case _ =>
+ false
+ })
def stat_<:<(that: Type): Boolean = {
if (Statistics.canEnable) Statistics.incCounter(subtypeCount)
val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, subtypeNanos) else null
val result =
(this eq that) ||
- (if (explainSwitch) explain("<:", isSubType, this, that)
- else isSubType(this, that, AnyDepth))
+ (if (explainSwitch) explain("<:", isSubType(_: Type, _: Type), this, that)
+ else isSubType(this, that))
if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
result
}
@@ -921,12 +832,7 @@ trait Types extends api.Types { self: SymbolTable =>
(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?
@@ -943,7 +849,7 @@ trait Types extends api.Types { self: SymbolTable =>
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)
+ def looselyMatches(that: Type): Boolean = matchesType(this, that, alwaysMatchSimple = true)
/** The shortest sorted upwards closed array of types that contains
* this type as first element.
@@ -968,10 +874,10 @@ trait Types extends api.Types { self: SymbolTable =>
/** The maximum depth (@see typeDepth)
* of each type in the BaseTypeSeq of this type except the first.
*/
- def baseTypeSeqDepth: Int = 1
+ def baseTypeSeqDepth: Depth = Depth(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 linearization order, starting with the class itself and ending
* in class Any.
*/
def baseClasses: List[Symbol] = List()
@@ -991,12 +897,12 @@ trait Types extends api.Types { self: SymbolTable =>
if (sym == btssym) return mid
else if (sym isLess btssym) hi = mid - 1
else if (btssym isLess sym) lo = mid + 1
- else abort()
+ else abort("sym is neither `sym == btssym`, `sym isLess btssym` nor `btssym isLess sym`")
}
-1
}
- /** If this is a poly- or methodtype, a copy with cloned type / value parameters
+ /** If this is a ExistentialType, PolyType or MethodType, a copy with cloned type / value parameters
* owned by `owner`. Identity for all other types.
*/
def cloneInfo(owner: Symbol) = this
@@ -1015,7 +921,11 @@ trait Types extends api.Types { self: SymbolTable =>
* after `maxTostringRecursions` recursion levels. Uses `safeToString`
* to produce a string on each level.
*/
- override def toString: String = typeToString(this)
+ override final def toString: String = {
+ // see comments to internal#Symbol.typeSignature for an explanation why this initializes
+ if (!isCompilerUniverse) fullyInitializeType(this)
+ typeToString(this)
+ }
/** Method to be implemented in subclasses.
* Converts this type to a string in calling toString for its parts.
@@ -1029,7 +939,9 @@ trait Types extends api.Types { self: SymbolTable =>
else if ((str endsWith ".type") && !typeSymbol.isModuleClass)
widen match {
case RefinedType(_, _) => "" + widen
- case _ => s"$str (with underlying type $widen)"
+ case _ =>
+ if (widen.toString.trim == "") str
+ else s"$str (with underlying type $widen)"
}
else str
}
@@ -1058,7 +970,7 @@ trait Types extends api.Types { self: SymbolTable =>
var sym: Symbol = NoSymbol
var e: ScopeEntry = decls.lookupEntry(name)
while (e ne null) {
- if (!e.sym.hasFlag(excludedFlags)) {
+ if (!e.sym.hasFlag(excludedFlags.toLong)) {
if (sym == NoSymbol) sym = e.sym
else {
if (alts.isEmpty) alts = sym :: Nil
@@ -1071,187 +983,38 @@ trait Types extends api.Types { self: SymbolTable =>
else (baseClasses.head.newOverloaded(this, alts))
}
+ /** Find all members meeting the flag requirements.
+ *
+ * If you require a DEFERRED member, you will get it if it exists -- even if there's an overriding concrete member.
+ * If you exclude DEFERRED members, or don't specify any requirements,
+ * you won't get deferred members (whether they have an overriding concrete member or not)
+ *
+ * Thus, findMember requiring DEFERRED flags yields deferred members,
+ * while `findMember(excludedFlags = 0, requiredFlags = 0).filter(_.isDeferred)` may not (if there's a corresponding concrete member)
+ *
+ * Requirements take precedence over exclusions, so requiring and excluding DEFERRED will yield a DEFERRED member (if there is one).
+ *
+ */
def findMembers(excludedFlags: Long, requiredFlags: Long): Scope = {
- // 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)
-
- if (Statistics.canEnable) Statistics.incCounter(findMembersCount)
- val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, findMembersNanos) else null
-
- //Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG
- var members: Scope = null
- var required = requiredFlags
- var excluded = excludedFlags | DEFERRED
- var continue = true
- var self: Type = null
- while (continue) {
- continue = false
- val bcs0 = baseClasses
- var bcs = bcs0
- while (!bcs.isEmpty) {
- val decls = bcs.head.info.decls
- var entry = decls.elems
- while (entry ne null) {
- val sym = entry.sym
- val flags = sym.flags
- if ((flags & required) == required) {
- val excl = flags & excluded
- if (excl == 0L &&
- (// omit PRIVATE LOCALS unless selector class is contained in class owning the def.
- (bcs eq bcs0) ||
- (flags & PrivateLocal) != PrivateLocal ||
- (bcs0.head.hasTransOwner(bcs.head)))) {
- if (members eq null) members = newFindMemberScope
- var others: ScopeEntry = members.lookupEntry(sym.name)
- var symtpe: Type = null
- while ((others ne null) && {
- val other = others.sym
- (other ne sym) &&
- ((other.owner eq sym.owner) ||
- (flags & PRIVATE) != 0 || {
- if (self eq null) self = narrowForFindMember(this)
- if (symtpe eq null) symtpe = self.memberType(sym)
- !(self.memberType(other) matches symtpe)
- })}) {
- others = members lookupNextEntry others
- }
- if (others eq null) members enter sym
- } else if (excl == DEFERRED) {
- continue = true
- }
- }
- entry = entry.next
- } // while (entry ne null)
- // excluded = excluded | LOCAL
- bcs = bcs.tail
- } // while (!bcs.isEmpty)
- required |= DEFERRED
- excluded &= ~(DEFERRED.toLong)
- } // while (continue)
- if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
- if (suspension ne null) suspension foreach (_.suspended = false)
- if (members eq null) EmptyScope else members
+ def findMembersInternal = new FindMembers(this, excludedFlags, requiredFlags).apply()
+ if (this.isGround) findMembersInternal
+ else suspendingTypeVars(typeVarsInType(this))(findMembersInternal)
}
/**
* 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 name The member's name
* @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)
-
- if (Statistics.canEnable) Statistics.incCounter(findMemberCount)
- val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, findMemberNanos) else null
-
- //Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG
- var member: Symbol = NoSymbol
- var members: List[Symbol] = null
- var lastM: ::[Symbol] = null
- var membertpe: Type = null
- var required = requiredFlags
- var excluded = excludedFlags | DEFERRED
- var continue = true
- var self: Type = null
-
- while (continue) {
- continue = false
- val bcs0 = baseClasses
- var bcs = bcs0
- // omit PRIVATE LOCALS unless selector class is contained in class owning the def.
- def admitPrivateLocal(owner: Symbol): Boolean = {
- val selectorClass = this match {
- case tt: ThisType => tt.sym // SI-7507 the first base class is not necessarily the selector class.
- case _ => bcs0.head
- }
- selectorClass.hasTransOwner(owner)
- }
- while (!bcs.isEmpty) {
- val decls = bcs.head.info.decls
- var entry = decls.lookupEntry(name)
- while (entry ne null) {
- val sym = entry.sym
- val flags = sym.flags
- if ((flags & required) == required) {
- val excl = flags & excluded
- if (excl == 0L &&
- (
- (bcs eq bcs0) ||
- (flags & PrivateLocal) != PrivateLocal ||
- admitPrivateLocal(bcs.head))) {
- if (name.isTypeName || stableOnly && sym.isStable) {
- if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
- if (suspension ne null) suspension foreach (_.suspended = false)
- return sym
- } else if (member eq NoSymbol) {
- member = sym
- } else if (members eq null) {
- if ((member ne sym) &&
- ((member.owner eq sym.owner) ||
- (flags & PRIVATE) != 0 || {
- if (self eq null) self = narrowForFindMember(this)
- if (membertpe eq null) membertpe = self.memberType(member)
- !(membertpe matches self.memberType(sym))
- })) {
- lastM = new ::(sym, null)
- members = member :: lastM
- }
- } else {
- var others: List[Symbol] = members
- var symtpe: Type = null
- while ((others ne null) && {
- val other = others.head
- (other ne sym) &&
- ((other.owner eq sym.owner) ||
- (flags & PRIVATE) != 0 || {
- if (self eq null) self = narrowForFindMember(this)
- if (symtpe eq null) symtpe = self.memberType(sym)
- !(self.memberType(other) matches symtpe)
- })}) {
- others = others.tail
- }
- if (others eq null) {
- val lastM1 = new ::(sym, null)
- lastM.tl = lastM1
- lastM = lastM1
- }
- }
- } else if (excl == DEFERRED) {
- continue = true
- }
- }
- entry = decls lookupNextEntry entry
- } // while (entry ne null)
- // excluded = excluded | LOCAL
- bcs = if (name == nme.CONSTRUCTOR) Nil else bcs.tail
- } // while (!bcs.isEmpty)
- required |= DEFERRED
- excluded &= ~(DEFERRED.toLong)
- } // while (continue)
- if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
- if (suspension ne null) suspension foreach (_.suspended = false)
- if (members eq null) {
- if (member == NoSymbol) if (Statistics.canEnable) Statistics.incCounter(noMemberCount)
- member
- } else {
- if (Statistics.canEnable) Statistics.incCounter(multMemberCount)
- lastM.tl = Nil
- baseClasses.head.newOverloaded(this, members)
- }
+ def findMemberInternal = new FindMember(this, name, excludedFlags, requiredFlags, stableOnly).apply()
+
+ if (this.isGround) findMemberInternal
+ else suspendingTypeVars(typeVarsInType(this))(findMemberInternal)
}
/** The (existential or otherwise) skolems and existentially quantified variables which are free in this type */
@@ -1280,17 +1043,6 @@ trait Types extends api.Types { self: SymbolTable =>
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()
}
@@ -1314,29 +1066,16 @@ trait Types extends api.Types { self: SymbolTable =>
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 baseTypeSeqDepth: Depth = 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 {
+ abstract class SingletonType extends SubType with SimpleTypeProxy with SingletonTypeApi {
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 = {
if (Statistics.canEnable) Statistics.incCounter(singletonBaseTypeSeqCount)
@@ -1350,7 +1089,6 @@ trait Types extends api.Types { self: SymbolTable =>
if (pre.isOmittablePrefix) pre.fullName + ".type"
else prefixString + "type"
}
-
/*
override def typeOfThis: Type = typeSymbol.typeOfThis
override def bounds: TypeBounds = TypeBounds(this, this)
@@ -1376,7 +1114,6 @@ trait Types extends api.Types { self: SymbolTable =>
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"
}
@@ -1386,7 +1123,6 @@ trait Types extends api.Types { self: SymbolTable =>
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
@@ -1411,38 +1147,32 @@ trait Types extends api.Types { self: SymbolTable =>
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 {
- if (!sym.isClass) {
+ if (!sym.isClass && !sym.isFreeType) {
// SI-6640 allow StubSymbols to reveal what's missing from the classpath before we trip the assertion.
sym.failIfStub()
abort(s"ThisType($sym) for sym which is not a class")
}
- //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."
+ if (settings.debug) sym.nameString + ".this."
else if (sym.isAnonOrRefinementClass) "this."
else if (sym.isOmittablePrefix) ""
else if (sym.isModuleClass) sym.fullNameString + "."
@@ -1460,7 +1190,7 @@ trait Types extends api.Types { self: SymbolTable =>
def apply(sym: Symbol): Type = (
if (!phase.erasedTypes) unique(new UniqueThisType(sym))
else if (sym.isImplClass) sym.typeOfThis
- else sym.tpe
+ else sym.tpe_*
)
}
@@ -1475,8 +1205,6 @@ trait Types extends api.Types { self: SymbolTable =>
}
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 = {
@@ -1490,8 +1218,6 @@ trait Types extends api.Types { self: SymbolTable =>
// 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
@@ -1531,7 +1257,7 @@ trait Types extends api.Types { self: SymbolTable =>
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;
+ tpe.underlyingCache = if (tpe.sym == NoSymbol) ThisType(rootMirror.RootClass) else tpe.pre.memberType(tpe.sym).resultType
assert(tpe.underlyingCache ne tpe, tpe)
}
}
@@ -1543,7 +1269,6 @@ trait Types extends api.Types { self: SymbolTable =>
if (trivial == UNKNOWN) trivial = fromBoolean(thistpe.isTrivial && supertpe.isTrivial)
toBoolean(trivial)
}
- override def isNotNull = true;
override def typeSymbol = thistpe.typeSymbol
override def underlying = supertpe
override def prefix: Type = supertpe.prefix
@@ -1571,31 +1296,52 @@ trait Types extends api.Types { self: SymbolTable =>
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 = typeIsNothing(lo)
- private def emptyUpperBound = typeIsAny(hi)
+ private def emptyLowerBound = typeIsNothing(lo) || lo.isWildcard
+ private def emptyUpperBound = typeIsAny(hi) || hi.isWildcard
def isEmptyBounds = emptyLowerBound && emptyUpperBound
- // override def isNullable: Boolean = NullClass.tpe <:< lo;
- override def safeToString = lowerString + upperString
+ override def safeToString = scalaNotation(_.toString)
+
+ /** Bounds notation used in Scala syntax.
+ * For example +This <: scala.collection.generic.Sorted[K,This].
+ */
+ private[internal] def scalaNotation(typeString: Type => String): String = {
+ (if (emptyLowerBound) "" else " >: " + typeString(lo)) +
+ (if (emptyUpperBound) "" else " <: " + typeString(hi))
+ }
+ /** Bounds notation used in http://adriaanm.github.com/files/higher.pdf.
+ * For example *(scala.collection.generic.Sorted[K,This]).
+ */
+ private[internal] def starNotation(typeString: Type => String): String = {
+ if (emptyLowerBound && emptyUpperBound) ""
+ else if (emptyLowerBound) "(" + typeString(hi) + ")"
+ else "(%s, %s)" format (typeString(lo), typeString(hi))
+ }
override def kind = "TypeBoundsType"
}
final class UniqueTypeBounds(lo: Type, hi: Type) extends TypeBounds(lo, hi)
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 empty: TypeBounds = apply(NothingTpe, AnyTpe)
+ def upper(hi: Type): TypeBounds = apply(NothingTpe, hi)
+ def lower(lo: Type): TypeBounds = apply(lo, AnyTpe)
def apply(lo: Type, hi: Type): TypeBounds = {
unique(new UniqueTypeBounds(lo, hi)).asInstanceOf[TypeBounds]
}
}
+ object CompoundType {
+ def unapply(tp: Type): Option[(List[Type], Scope, Symbol)] = tp match {
+ case ClassInfoType(parents, decls, clazz) => Some((parents, decls, clazz))
+ case RefinedType(parents, decls) => Some((parents, decls, tp.typeSymbol))
+ case _ => None
+ }
+ }
+
/** A common base class for intersection types and class types
*/
- abstract class CompoundType extends Type {
+ abstract class CompoundType extends Type with CompoundTypeApi {
private[reflect] var baseTypeSeqCache: BaseTypeSeq = _
private[reflect] var baseTypeSeqPeriod = NoPeriod
@@ -1615,7 +1361,7 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
- override def baseTypeSeqDepth: Int = baseTypeSeq.maxDepth
+ override def baseTypeSeqDepth: Depth = baseTypeSeq.maxDepth
override def baseClasses: List[Symbol] = {
val cached = baseClassesCache
@@ -1657,18 +1403,46 @@ trait Types extends api.Types { self: SymbolTable =>
}
override def narrow: Type = typeSymbol.thisType
- override def isNotNull: Boolean = parents exists typeIsNotNull
override def isStructuralRefinement: Boolean =
typeSymbol.isAnonOrRefinementClass && (decls exists symbolIsPossibleInRefinement)
- // override def isNullable: Boolean =
- // parents forall (p => p.isNullable && !p.typeSymbol.isAbstractType);
+ protected def shouldForceScope = settings.debug || parents.isEmpty || !decls.isEmpty
+ protected def initDecls = fullyInitializeScope(decls)
+ protected def scopeString = if (shouldForceScope) initDecls.mkString("{", "; ", "}") else ""
+ override def safeToString = parentsString(parents) + scopeString
+ }
- override def safeToString: String = parentsString(parents) + (
- (if (settings.debug.value || parents.isEmpty || (decls.elems ne null))
- fullyInitializeScope(decls).mkString("{", "; ", "}") else "")
+ protected def computeBaseClasses(tpe: Type): List[Symbol] = {
+ val parents = tpe.parents // adriaan says tpe.parents does work sometimes, so call it only once
+ val baseTail = (
+ if (parents.isEmpty || parents.head.isInstanceOf[PackageTypeRef]) Nil
+ else {
+ //Console.println("computing base classes of " + typeSymbol + " at phase " + phase);//DEBUG
+ // optimized, since this seems to be performance critical
+ val superclazz = parents.head // parents.isEmpty was already excluded
+ var mixins = 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
+ }
+ bcs
+ }
)
+ tpe.typeSymbol :: baseTail
}
protected def defineBaseTypeSeqOfCompoundType(tpe: CompoundType) = {
@@ -1690,7 +1464,7 @@ trait Types extends api.Types { self: SymbolTable =>
val paramToVarMap = varToParamMap map (_.swap)
val varToParam = new TypeMap {
def apply(tp: Type) = varToParamMap get tp match {
- case Some(sym) => sym.tpe
+ case Some(sym) => sym.tpe_*
case _ => mapOver(tp)
}
}
@@ -1709,7 +1483,7 @@ trait Types extends api.Types { self: SymbolTable =>
tpe.baseTypeSeqCache = undetBaseTypeSeq
tpe.baseTypeSeqCache =
if (tpe.typeSymbol.isRefinementClass)
- tpe.memo(compoundBaseTypeSeq(tpe))(_.baseTypeSeq updateHead tpe.typeSymbol.tpe)
+ tpe.memo(compoundBaseTypeSeq(tpe))(_.baseTypeSeq updateHead tpe.typeSymbol.tpe_*)
else
compoundBaseTypeSeq(tpe)
} finally {
@@ -1731,41 +1505,61 @@ trait Types extends api.Types { self: SymbolTable =>
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
+ object baseClassesCycleMonitor {
+ private var open: List[Symbol] = Nil
+ @inline private def cycleLog(msg: => String) {
+ if (settings.debug)
+ Console.err.println(msg)
+ }
+ def size = open.size
+ def push(clazz: Symbol) {
+ cycleLog("+ " + (" " * size) + clazz.fullNameString)
+ open ::= clazz
+ }
+ def pop(clazz: Symbol) {
+ assert(open.head eq clazz, (clazz, open))
+ open = open.tail
+ }
+ def isOpen(clazz: Symbol) = open contains clazz
+ }
+
+ protected def defineBaseClassesOfCompoundType(tpe: CompoundType) {
+ def define() = defineBaseClassesOfCompoundType(tpe, force = false)
+ if (!breakCycles || isPastTyper) define()
+ else tpe match {
+ // non-empty parents helpfully excludes all package classes
+ case tpe @ ClassInfoType(_ :: _, _, clazz) if !clazz.isAnonOrRefinementClass =>
+ // Cycle: force update
+ if (baseClassesCycleMonitor isOpen clazz)
+ defineBaseClassesOfCompoundType(tpe, force = true)
+ else {
+ baseClassesCycleMonitor push clazz
+ try define()
+ finally baseClassesCycleMonitor pop clazz
}
- tpe.typeSymbol :: bcs
- }
+ case _ =>
+ define()
+ }
+ }
+ private def defineBaseClassesOfCompoundType(tpe: CompoundType, force: Boolean) {
val period = tpe.baseClassesPeriod
- if (period != currentPeriod) {
+ if (period == currentPeriod) {
+ if (force && breakCycles) {
+ def what = tpe.typeSymbol + " in " + tpe.typeSymbol.owner.fullNameString
+ val bcs = computeBaseClasses(tpe)
+ tpe.baseClassesCache = bcs
+ warning(s"Breaking cycle in base class computation of $what ($bcs)")
+ }
+ }
+ else {
tpe.baseClassesPeriod = currentPeriod
if (!isValidForBaseClasses(period)) {
val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, baseClassesNanos) else null
try {
tpe.baseClassesCache = null
- tpe.baseClassesCache = tpe.memo(computeBaseClasses)(tpe.typeSymbol :: _.baseClasses.tail)
- } finally {
+ tpe.baseClassesCache = tpe.memo(computeBaseClasses(tpe))(tpe.typeSymbol :: _.baseClasses.tail)
+ }
+ finally {
if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
}
}
@@ -1813,47 +1607,27 @@ trait Types extends api.Types { self: SymbolTable =>
} 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))
+ etaExpand
} 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
- }))
+ final override def etaExpand: Type = {
+ // 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
+ // !!! inconsistent with TypeRef.etaExpand that uses initializedTypeParams
+ if (!isHigherKinded) this
+ else typeFun(
+ typeParams,
+ RefinedType(
+ parents map {
+ case TypeRef(pre, sym, List()) => TypeRef(pre, sym, dummyArgs)
+ case p => p
+ },
+ decls,
+ typeSymbol))
}
+
override def kind = "RefinedType"
}
@@ -1960,8 +1734,8 @@ trait Types extends api.Types { self: SymbolTable =>
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)
+ if (settings.debug && !sameLength(tparams, args))
+ devWarning(s"Mismatched zip in computeRefs(): ${sym.info.typeParams}, $args")
foreach2(tparams, args) { (tparam1, arg) =>
if (arg contains tparam) {
@@ -2004,7 +1778,7 @@ trait Types extends api.Types { self: SymbolTable =>
var change = false
for ((from, targets) <- refs(NonExpansive).iterator)
for (target <- targets) {
- var thatInfo = classInfo(target)
+ val thatInfo = classInfo(target)
if (thatInfo.state != Initialized)
change = change | thatInfo.propagate()
addRefs(NonExpansive, from, thatInfo.getRefs(NonExpansive, target))
@@ -2012,7 +1786,7 @@ trait Types extends api.Types { self: SymbolTable =>
}
for ((from, targets) <- refs(Expansive).iterator)
for (target <- targets) {
- var thatInfo = classInfo(target)
+ val thatInfo = classInfo(target)
if (thatInfo.state != Initialized)
change = change | thatInfo.propagate()
addRefs(Expansive, from, thatInfo.getRefs(NonExpansive, target))
@@ -2023,27 +1797,13 @@ trait Types extends api.Types { self: SymbolTable =>
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))
- fullyInitializeScope(decls).mkString(" {\n ", "\n ", "\n}")
- else ""
- )
+ def formattedToString = parents.mkString("\n with ") + scopeString
+ override protected def shouldForceScope = settings.debug || decls.size > 1
+ override protected def scopeString = initDecls.mkString(" {\n ", "\n ", "\n}")
+ override def safeToString = if (shouldForceScope) formattedToString else super.safeToString
}
object ClassInfoType extends ClassInfoTypeExtractor
@@ -2052,19 +1812,14 @@ trait Types extends api.Types { self: SymbolTable =>
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 deconst: Type = underlying.deconst
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"
}
@@ -2082,7 +1837,7 @@ trait Types extends api.Types { self: SymbolTable =>
private val pendingVolatiles = new mutable.HashSet[Symbol]
class ArgsTypeRef(pre0: Type, sym0: Symbol, args0: List[Type]) extends TypeRef(pre0, sym0, args0) {
- require(args0.nonEmpty, this)
+ require(args0 ne Nil, this)
/** No unapplied type params size it has (should have) equally as many args. */
override def isHigherKinded = false
@@ -2093,10 +1848,39 @@ trait Types extends api.Types { self: SymbolTable =>
// 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)
+ val tparams = sym.typeParams
+ if (tparams.size != args.size)
+ devWarning(s"$this.transform($tp), but tparams.isEmpty and args=$args")
+ def asSeenFromInstantiated(tp: Type) =
+ asSeenFromOwner(tp).instantiateTypeParams(tparams, args)
+ // If we're called with a poly type, and we were to run the `asSeenFrom`, over the entire
+ // type, we can end up with new symbols for the type parameters (clones from TypeMap).
+ // The subsequent substitution of type arguments would fail. This problem showed up during
+ // the fix for SI-8046, however the solution taken there wasn't quite right, and led to
+ // SI-8170.
+ //
+ // Now, we detect the PolyType before both the ASF *and* the substitution, and just operate
+ // on the result type.
+ //
+ // TODO: Revisit this and explore the questions raised:
+ //
+ // AM: I like this better than the old code, but is there any way the tparams would need the ASF treatment as well?
+ // JZ: I think its largely irrelevant, as they are no longer referred to in the result type.
+ // In fact, you can get away with returning a type of kind * here and the sky doesn't fall:
+ // `case PolyType(`tparams`, result) => asSeenFromInstantiated(result)`
+ // But I thought it was better to retain the kind.
+ // AM: I've been experimenting with apply-type-args-then-ASF, but running into cycles.
+ // In general, it seems iffy the tparams can never occur in the result
+ // then we might as well represent the type as a no-arg typeref.
+ // AM: I've also been trying to track down uses of transform (pretty generic name for something that
+ // does not seem that widely applicable).
+ // It's kind of a helper for computing baseType (since it tries to propagate our type args to some
+ // other type, which has to be related to this type for that to make sense).
+ //
+ tp match {
+ case PolyType(`tparams`, result) => PolyType(tparams, asSeenFromInstantiated(result))
+ case _ => asSeenFromInstantiated(tp)
+ }
}
// note: does not go through typeRef. There's no need to because
@@ -2108,14 +1892,12 @@ trait Types extends api.Types { self: SymbolTable =>
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
@@ -2140,7 +1922,7 @@ trait Types extends api.Types { self: SymbolTable =>
// 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 isHigherKinded = (typeParams ne Nil)
override def typeParams = if (isDefinitionsInitialized) sym.typeParams else sym.unsafeTypeParams
private def isRaw = !phase.erasedTypes && isRawIfWithoutArgs(sym)
@@ -2230,8 +2012,6 @@ trait Types extends api.Types { self: SymbolTable =>
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
@@ -2252,7 +2032,7 @@ trait Types extends api.Types { self: SymbolTable =>
else ErrorType
}
- // isHKSubType0 introduces synthetic type params so that
+ // isHKSubType 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
@@ -2262,22 +2042,51 @@ trait Types extends api.Types { self: SymbolTable =>
// appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner)
override 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
- }
+ /** SI-3731, SI-8177: when prefix is changed to `newPre`, maintain consistency of prefix and sym
+ * (where the symbol refers to a declaration "embedded" in the prefix).
+ *
+ * @returns newSym so that `newPre` binds `sym.name` to `newSym`,
+ * to remain consistent with `pre` previously binding `sym.name` to `sym`.
+ *
+ * `newSym` and `sym` are conceptually the same symbols, but some change to our `prefix`
+ * got them out of whack. (Usually triggered by substitution or `asSeenFrom`.)
+ * The only kind of "binds" we consider is where `prefix` (or its underlying type)
+ * is a refined type that declares `sym` (since the old prefix was discarded,
+ * the old symbol is now stale and we should update it, like in `def rebind`,
+ * except this is not for overriding symbols -- a vertical move -- but a "lateral" change.)
+ *
+ * The reason for this hack is that substitution and asSeenFrom clone RefinedTypes and
+ * their members, without updating the potential references to those members -- here, we aim to patch
+ * this up, so that: when changing a TypeRef(pre, sym, args) to a TypeRef(pre', sym', args'), and pre
+ * embeds a symbol sym (pre is a RefinedType(_, Scope(..., sym,...)) or a SingleType with such an
+ * underlying type), make sure that we update sym' to compensate for the change of pre -> pre' (which may
+ * have created a new symbol for the one the original sym referred to)
+ */
+ override def coevolveSym(newPre: Type): Symbol =
+ if ((pre ne newPre) && embeddedSymbol(pre, sym.name) == sym) {
+ val newSym = embeddedSymbol(newPre, sym.name)
+ debuglog(s"co-evolve: ${pre} -> ${newPre}, $sym : ${sym.info} -> $newSym : ${newSym.info}")
+ // To deal with erroneous `preNew`, fallback via `orElse sym`, in case `preNew` does not have a decl named `sym.name`.
+ newSym orElse sym
+ } else sym
+
override def kind = "AliasTypeRef"
}
+ // Return the symbol named `name` that's "embedded" in tp
+ // This is the case if `tp` is a `T{...; type/val $name ; ...}`,
+ // or a singleton type with such an underlying type.
+ private def embeddedSymbol(tp: Type, name: Name): Symbol =
+ // normalize to flatten nested RefinedTypes
+ // don't check whether tp is a RefinedType -- it may be a ThisType of one, for example
+ // TODO: check the resulting symbol is owned by the refinement class? likely an invariant...
+ if (tp.typeSymbol.isRefinementClass) tp.normalize.decls lookup name
+ else {
+ debuglog(s"no embedded symbol $name found in ${showRaw(tp)} --> ${tp.normalize.decls lookup name}")
+ NoSymbol
+ }
+
+
trait AbstractTypeRef extends NonClassTypeRef {
require(sym.isAbstractType, sym)
@@ -2286,30 +2095,6 @@ trait Types extends api.Types { self: SymbolTable =>
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)) {
@@ -2324,9 +2109,7 @@ trait Types extends api.Types { self: SymbolTable =>
}
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"
}
@@ -2345,6 +2128,10 @@ trait Types extends api.Types { self: SymbolTable =>
trivial = fromBoolean(!sym.isTypeParameter && pre.isTrivial && areTrivialTypes(args))
toBoolean(trivial)
}
+ private[scala] def invalidateCaches(): Unit = {
+ parentsPeriod = NoPeriod
+ baseTypeSeqPeriod = NoPeriod
+ }
private[reflect] var parentsCache: List[Type] = _
private[reflect] var parentsPeriod = NoPeriod
private[reflect] var baseTypeSeqCache: BaseTypeSeq = _
@@ -2354,12 +2141,12 @@ trait Types extends api.Types { self: SymbolTable =>
//OPT specialize hashCode
override final def computeHashCode = {
import scala.util.hashing.MurmurHash3._
- val hasArgs = args.nonEmpty
+ val hasArgs = args ne Nil
var h = productSeed
h = mix(h, pre.hashCode)
h = mix(h, sym.hashCode)
if (hasArgs)
- finalizeHash(mix(h, args.hashCode), 3)
+ finalizeHash(mix(h, args.hashCode()), 3)
else
finalizeHash(h, 2)
}
@@ -2390,7 +2177,7 @@ trait Types extends api.Types { self: SymbolTable =>
|| pre.isGround && args.forall(_.isGround)
)
- override def etaExpand: Type = {
+ final override def etaExpand: Type = {
// must initialise symbol, see test/files/pos/ticket0137.scala
val tpars = initializedTypeParams
if (tpars.isEmpty) this
@@ -2411,7 +2198,6 @@ trait Types extends api.Types { self: SymbolTable =>
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
@@ -2420,9 +2206,6 @@ trait Types extends api.Types { self: SymbolTable =>
override def typeSymbol = sym
override def typeSymbolDirect = sym
- 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
@@ -2440,8 +2223,14 @@ trait Types extends api.Types { self: SymbolTable =>
}
thisInfo.decls
}
-
- protected[Types] def baseTypeSeqImpl: BaseTypeSeq = sym.info.baseTypeSeq map transform
+ protected[Types] def baseTypeSeqImpl: BaseTypeSeq =
+ if (sym.info.baseTypeSeq exists (_.typeSymbolDirect.isAbstractType))
+ // SI-8046 base type sequence might have more elements in a subclass, we can't map it element wise.
+ transform(sym.info).baseTypeSeq
+ else
+ // Optimization: no abstract types, we can compute the BTS of this TypeRef as an element-wise map
+ // of the BTS of the referenced symbol.
+ sym.info.baseTypeSeq map transform
override def baseTypeSeq: BaseTypeSeq = {
val cache = baseTypeSeqCache
@@ -2455,66 +2244,69 @@ trait Types extends api.Types { self: SymbolTable =>
baseTypeSeqCache
}
}
-
// ensure that symbol is not a local copy with a name coincidence
private def needsPreString = (
- settings.debug.value
+ settings.debug
|| !shorthands(sym.fullName)
|| (sym.ownersIterator 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) (
- fullyInitializeScope(decls) filter (sym => sym.isPossibleInRefinement && sym.isPublic)
- map (_.defString)
- mkString("{", "; ", "}")
- )
+ private def refinementDecls = fullyInitializeScope(decls) filter (sym => sym.isPossibleInRefinement && sym.isPublic)
+ private def refinementString = (
+ if (sym.isStructuralRefinement)
+ refinementDecls map (_.defString) mkString("{", "; ", "}")
else ""
)
-
protected def finishPrefix(rest: String) = (
if (sym.isInitialized && sym.isAnonymousClass && !phase.erasedTypes)
parentsString(thisInfo.parents) + refinementString
else rest
)
+ private def noArgsString = finishPrefix(preString + sym.nameString)
+ private def tupleTypeString: String = args match {
+ case Nil => noArgsString
+ case arg :: Nil => s"($arg,)"
+ case _ => args.mkString("(", ", ", ")")
+ }
private def customToString = sym match {
- case RepeatedParamClass => args.head + "*"
+ case RepeatedParamClass | JavaRepeatedParamClass => args.head + "*"
case ByNameParamClass => "=> " + args.head
case _ =>
- def targs = normalize.typeArgs
-
- if (isFunctionType(this)) {
+ if (isFunctionTypeDirect(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) =>
+ unspecializedTypeArgs(this) match {
+ // See neg/t588 for an example which arrives here - printing
+ // the type of a Function1 after erasure.
+ case Nil => noArgsString
+ case in :: out :: Nil if !isTupleTypeDirect(in) =>
// A => B => C should be (A => B) => C or A => (B => C).
// Also if A is byname, then we want (=> A) => B because => is right associative and => A => B
// would mean => (A => B) which is a different type
- val in_s = if (isFunctionType(in) || isByNameParamType(in)) "(" + in + ")" else "" + in
- val out_s = if (isFunctionType(out)) "(" + out + ")" else "" + out
+ val in_s = if (isFunctionTypeDirect(in) || isByNameParamType(in)) "(" + in + ")" else "" + in
+ val out_s = if (isFunctionTypeDirect(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 if (isTupleTypeDirect(this))
+ tupleTypeString
+ else if (sym.isAliasType && prefixChain.exists(_.termSymbol.isSynthetic) && (this ne dealias))
+ "" + dealias
else
""
}
override def safeToString = {
- val custom = if (settings.debug.value) "" else customToString
+ val custom = if (settings.debug) "" else customToString
if (custom != "") custom
else finishPrefix(preString + sym.nameString + argsString)
}
override def prefixString = "" + (
- if (settings.debug.value)
+ if (settings.debug)
super.prefixString
else if (sym.isOmittablePrefix)
""
@@ -2525,23 +2317,33 @@ trait Types extends api.Types { self: SymbolTable =>
else
super.prefixString
)
+ // Suppressing case class copy method which risks subverting our single point of creation.
+ private def copy = null
override def kind = "TypeRef"
}
+ // No longer defined as anonymous classes in `object TypeRef` to avoid an unnecessary outer pointer.
+ private final class AliasArgsTypeRef(pre: Type, sym: Symbol, args: List[Type]) extends ArgsTypeRef(pre, sym, args) with AliasTypeRef
+ private final class AbstractArgsTypeRef(pre: Type, sym: Symbol, args: List[Type]) extends ArgsTypeRef(pre, sym, args) with AbstractTypeRef
+ private final class ClassArgsTypeRef(pre: Type, sym: Symbol, args: List[Type]) extends ArgsTypeRef(pre, sym, args) with ClassTypeRef
+ private final class AliasNoArgsTypeRef(pre: Type, sym: Symbol) extends NoArgsTypeRef(pre, sym) with AliasTypeRef
+ private final class AbstractNoArgsTypeRef(pre: Type, sym: Symbol) extends NoArgsTypeRef(pre, sym) with AbstractTypeRef
+ private final class ClassNoArgsTypeRef(pre: Type, sym: Symbol) extends NoArgsTypeRef(pre, sym) with ClassTypeRef
+
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
+ if (args ne Nil) {
+ if (sym.isAliasType) new AliasArgsTypeRef(pre, sym, args)
+ else if (sym.isAbstractType) new AbstractArgsTypeRef(pre, sym, args)
+ else new ClassArgsTypeRef(pre, sym, args)
}
else {
- if (sym.isAliasType) new NoArgsTypeRef(pre, sym) with AliasTypeRef
- else if (sym.isAbstractType) new NoArgsTypeRef(pre, sym) with AbstractTypeRef
+ if (sym.isAliasType) new AliasNoArgsTypeRef(pre, sym)
+ else if (sym.isAbstractType) new AbstractNoArgsTypeRef(pre, sym)
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
+ else new ClassNoArgsTypeRef(pre, sym)
}
})
}
@@ -2553,7 +2355,7 @@ trait Types extends api.Types { self: SymbolTable =>
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)
+ tpe.parentsCache = List(AnyTpe)
}
}
}
@@ -2603,7 +2405,7 @@ trait Types extends api.Types { self: SymbolTable =>
true
}
- def isImplicit = params.nonEmpty && params.head.isImplicit
+ def isImplicit = (params ne Nil) && 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
@@ -2611,7 +2413,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def paramss: List[List[Symbol]] = params :: resultType.paramss
- override def paramTypes = params map (_.tpe)
+ override def paramTypes = mapList(params)(symTpe) // OPT use mapList rather than .map
override def boundSyms = resultType.boundSyms ++ params
@@ -2634,8 +2436,6 @@ trait Types extends api.Types { self: SymbolTable =>
//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) = {
@@ -2662,17 +2462,15 @@ trait Types extends api.Types { self: SymbolTable =>
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 baseTypeSeqDepth: Depth = 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"
}
@@ -2707,12 +2505,10 @@ trait Types extends api.Types { self: SymbolTable =>
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 baseTypeSeqDepth: Depth = 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
@@ -2757,7 +2553,6 @@ trait Types extends api.Types { self: SymbolTable =>
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
@@ -2781,8 +2576,59 @@ trait Types extends api.Types { self: SymbolTable =>
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)
+ // TODO: check invariant that all quantifiers have the same (existing) owner
+ private def quantifierOwner = quantified collectFirst { case q if q.owner.exists => q.owner } getOrElse NoSymbol
+
+ // Is this existential of the form: T[Q1, ..., QN] forSome { type Q1 >: L1 <: U1, ..., QN >: LN <: UN}
+ private def isStraightApplication = (quantified corresponds underlying.typeArgs){ (q, a) => q.tpe =:= a }
+
+ /** [SI-6169, SI-8197 -- companion to SI-1786]
+ *
+ * Approximation to improve the bounds of a Java-defined existential type,
+ * based on the bounds of the type parameters of the quantified type
+ * In Scala syntax, given a java-defined class C[T <: String], the existential type C[_]
+ * is improved to C[_ <: String] before skolemization, which captures (get it?) what Java does:
+ * enter the type paramers' bounds into the context when checking subtyping/type equality of existential types
+ *
+ * Also tried doing this once during class file parsing or when creating the existential type,
+ * but that causes cyclic errors because it happens too early.
+ *
+ * NOTE: we're only modifying the skolems to avoid leaking the sharper bounds to `quantified` (SI-8283)
+ *
+ * TODO: figure out how to do this earlier without running into cycles, so this can subsume the fix for SI-1786
+ */
+ override def skolemizeExistential(owner0: Symbol, origin: AnyRef) = {
+ val owner = owner0 orElse quantifierOwner
+
+ // do this here because it's quite close to what Java does:
+ // when checking subtyping/type equality, enter constraints
+ // derived from the existentially quantified type into the typing environment
+ // (aka \Gamma, which tracks types for variables and constraints/kinds for types)
+ // as a nice bonus, delaying this until we need it avoids cyclic errors
+ def tpars = underlying.typeSymbol.initialize.typeParams
+
+ def newSkolem(quant: Symbol) = owner.newExistentialSkolem(quant, origin)
+ def newSharpenedSkolem(quant: Symbol, tparam: Symbol): Symbol = {
+ def emptyBounds(sym: Symbol) = sym.info.bounds.isEmptyBounds
+
+ // avoid creating cycles [pos/t2940] that consist of an existential quantifier's
+ // bounded by an existential type that unhygienically has that quantifier as its own quantifier
+ // (TODO: clone latter existential with fresh quantifiers -- not covering this case for now)
+ val canSharpen = (
+ emptyBounds(quant) && !emptyBounds(tparam)
+ && (existentialsInType(tparam.info) intersect quantified).isEmpty
+ )
+
+ val skolemInfo = if (!canSharpen) quant.info else tparam.info.substSym(tpars, quantified)
+
+ owner.newExistentialSkolem(quant.name.toTypeName, skolemInfo, quant.flags, quant.pos, origin)
+ }
+
+ val canSharpenBounds = (underlying.typeSymbol.isJavaDefined || sharperSkolems) && isStraightApplication
+
+ if (canSharpenBounds) deriveType2(quantified, tpars, newSharpenedSkolem)(underlying)
+ else deriveType(quantified, newSkolem)(underlying)
+ }
private def wildcardArgsString(qset: Set[Symbol], args: List[Type]): List[String] = args map {
case TypeRef(_, sym, _) if (qset contains sym) =>
@@ -2820,10 +2666,10 @@ trait Types extends api.Types { self: SymbolTable =>
override def safeToString: String = {
def clauses = {
val str = quantified map (_.existentialToString) mkString (" forSome { ", "; ", " }")
- if (settings.explaintypes.value) "(" + str + ")" else str
+ if (settings.explaintypes) "(" + str + ")" else str
}
underlying match {
- case TypeRef(pre, sym, args) if !settings.debug.value && isRepresentableWithWildcards =>
+ case TypeRef(pre, sym, args) if !settings.debug && isRepresentableWithWildcards =>
"" + TypeRef(pre, sym, Nil) + wildcardArgsString(quantified.toSet, args).mkString("[", ", ", "]")
case MethodType(_, _) | NullaryMethodType(_) | PolyType(_, _) =>
"(" + underlying + ")" + clauses
@@ -2842,13 +2688,13 @@ trait Types extends api.Types { self: SymbolTable =>
def withTypeVars(op: Type => Boolean): Boolean = withTypeVars(op, AnyDepth)
- def withTypeVars(op: Type => Boolean, depth: Int): Boolean = {
+ def withTypeVars(op: Type => Boolean, depth: Depth): 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))
+ solve(tvars, quantifiedFresh, quantifiedFresh map (_ => Invariant), upper = false, depth) &&
+ isWithinBounds(NoPrefix, NoSymbol, quantifiedFresh, tvars map (_.inst))
}
}
}
@@ -2865,9 +2711,17 @@ trait Types extends api.Types { self: SymbolTable =>
override def kind = "OverloadedType"
}
- def overloadedType(pre: Type, alternatives: List[Symbol]): Type =
- if (alternatives.tail.isEmpty) pre memberType alternatives.head
- else OverloadedType(pre, alternatives)
+ /** The canonical creator for OverloadedTypes.
+ */
+ def overloadedType(pre: Type, alternatives: List[Symbol]): Type = alternatives match {
+ case Nil => NoType
+ case alt :: Nil => pre memberType alt
+ case _ => OverloadedType(pre, alternatives)
+ }
+
+ case class ImportType(expr: Tree) extends Type {
+ override def safeToString = "ImportType("+expr+")"
+ }
/** A class remembering a type instantiation for some a set of overloaded
* polymorphic symbols.
@@ -2875,23 +2729,12 @@ trait Types extends api.Types { self: SymbolTable =>
*/
case class AntiPolyType(pre: Type, targs: List[Type]) extends Type {
override def safeToString =
- pre.toString + targs.mkString("(with type arguments ", ", ", ")");
+ 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)
@@ -2906,13 +2749,10 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
- // 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
+ object ArrayTypeRef {
+ def unapply(tp: Type) = tp match {
+ case TypeRef(_, ArrayClass, arg :: Nil) => Some(arg)
+ case _ => None
}
}
@@ -2941,10 +2781,10 @@ trait Types extends api.Types { self: SymbolTable =>
* 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.
+ /* 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 typeIsNonClassType)
@@ -2985,20 +2825,6 @@ trait Types extends api.Types { self: SymbolTable =>
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 typeIsExistentiallyBound
-
- def existentialsInType(tpe: Type) =
- tpe withFilter typeIsExistentiallyBound map (_.typeSymbol)
-
/** Precondition: params.nonEmpty. (args.nonEmpty enforced structurally.)
*/
class HKTypeVar(
@@ -3009,7 +2835,6 @@ trait Types extends api.Types { self: SymbolTable =>
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.)
@@ -3025,9 +2850,7 @@ trait Types extends api.Types { self: SymbolTable =>
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 + "[", ", ", "]")
- )
+ override def safeToString: String = super.safeToString + typeArgs.map(_.safeToString).mkString("[", ", ", "]")
}
trait UntouchableTypeVar extends TypeVar {
@@ -3057,7 +2880,7 @@ trait Types extends api.Types { self: SymbolTable =>
* Precondition for this class, enforced structurally: args.isEmpty && params.isEmpty.
*/
abstract case class TypeVar(
- val origin: Type,
+ origin: Type,
var constr: TypeConstraint
) extends Type {
@@ -3077,9 +2900,10 @@ trait Types extends api.Types { self: SymbolTable =>
* 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
+ def inst = constr.inst
+ def instWithinBounds = constr.instWithinBounds
+ override def isGround = instValid && inst.isGround
/** The variable's skolemization level */
val level = skolemizationLevel
@@ -3098,6 +2922,7 @@ trait Types extends api.Types { self: SymbolTable =>
this
else if (newArgs.size == params.size) {
val tv = TypeVar(origin, constr, newArgs, params)
+ tv.linkSuspended(this)
TypeVar.trace("applyArgs", "In " + originLocation + ", apply args " + newArgs.mkString(", ") + " to " + originName)(tv)
}
else
@@ -3120,8 +2945,7 @@ trait Types extends api.Types { self: SymbolTable =>
// 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.
+ // typevar, which means we'll need to repack our 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
@@ -3132,7 +2956,10 @@ trait Types extends api.Types { self: SymbolTable =>
// 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): this.type = {
-// assert(!(tp containsTp this), this)
+ if (tp eq this) {
+ log(s"TypeVar cycle: called setInst passing $this to itself.")
+ return 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
@@ -3144,20 +2971,43 @@ trait Types extends api.Types { self: SymbolTable =>
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)
+ if (!sharesConstraints(tp)) {
+ 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)
+ if (!sharesConstraints(tp)) {
+ undoLog record this
+ constr.addHiBound(tp, isNumericBound)
+ }
}
// </region>
// ignore subtyping&equality checks while true -- see findMember
- private[Types] var suspended = false
+ // OPT: This could be Either[TypeVar, Boolean], but this encoding was chosen instead to save allocations.
+ private var _suspended: Type = ConstantFalse
+ private[Types] def suspended: Boolean = (_suspended: @unchecked) match {
+ case ConstantFalse => false
+ case ConstantTrue => true
+ case tv: TypeVar => tv.suspended
+ }
+
+ /** `AppliedTypeVar`s share the same `TypeConstraint` with the `HKTypeVar` that it was spawned from.
+ * A type inference session can also have more than one ATV.
+ * If we don't detect that, we end up with "cyclic constraint" when we try to instantiate type parameters
+ * after solving in, pos/t8237
+ */
+ protected final def sharesConstraints(other: Type): Boolean = other match {
+ case other: TypeVar => constr == other.constr // SI-8237 avoid cycles. Details in pos/t8237.scala
+ case _ => false
+ }
+ private[Types] def suspended_=(b: Boolean): Unit = _suspended = if (b) ConstantTrue else ConstantFalse
+ // SI-7785 Link the suspended attribute of a TypeVar created in, say, a TypeMap (e.g. AsSeenFrom) to its originator
+ private[Types] def linkSuspended(origin: TypeVar): Unit = _suspended = origin
/** 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,
@@ -3187,7 +3037,7 @@ trait Types extends api.Types { self: SymbolTable =>
else lhs <:< rhs
}
- /** Simple case: type arguments can be ignored, because either this typevar has
+ /* 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
@@ -3214,7 +3064,7 @@ trait Types extends api.Types { self: SymbolTable =>
} else false
}
- /** Full case: involving a check of the form
+ /* Full case: involving a check of the form
* {{{
* TC1[T1,..., TN] <: TC2[T'1,...,T'N]
* }}}
@@ -3263,8 +3113,8 @@ trait Types extends api.Types { self: SymbolTable =>
// 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 if (instValid) // type var is already set
+ checkSubtype(tp, inst)
else isRelatable(tp) && {
unifySimple || unifyFull(tp) || (
// only look harder if our gaze is oriented toward Any
@@ -3280,17 +3130,20 @@ trait Types extends api.Types { self: SymbolTable =>
}
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
+// println("regTypeEq: "+(safeToString, debugString(tp), tp.getClass, if (typeVarLHS) "in LHS" else "in RHS", if (suspended) "ZZ" else if (instValid) "IV" else "")) //@MDEBUG
+ def checkIsSameType(tp: Type) = (
+ if (typeVarLHS) inst =:= tp
+ else tp =:= inst
+ )
if (suspended) tp =:= origin
- else if (constr.instValid) checkIsSameType(tp)
+ else if (instValid) checkIsSameType(tp)
else isRelatable(tp) && {
val newInst = wildcardToTypeVarMap(tp)
- (constr isWithinBounds newInst) && { setInst(tp); true }
+ (constr isWithinBounds newInst) && {
+ setInst(newInst)
+ true
+ }
}
}
@@ -3301,7 +3154,7 @@ trait Types extends api.Types { self: SymbolTable =>
* (`T` corresponds to @param sym)
*/
def registerTypeSelection(sym: Symbol, tp: Type): Boolean = {
- registerBound(HasTypeMember(sym.name.toTypeName, tp), false)
+ registerBound(HasTypeMember(sym.name.toTypeName, tp), isLowerBound = false)
}
private def isSkolemAboveLevel(tp: Type) = tp.typeSymbol match {
@@ -3323,15 +3176,17 @@ trait Types extends api.Types { self: SymbolTable =>
)
override def normalize: Type = (
- if (constr.instValid) constr.inst
+ if (instValid) inst
// get here when checking higher-order subtyping of the typevar by itself
// TODO: check whether this ever happens?
- else if (isHigherKinded) logResult("Normalizing HK $this")(typeFun(params, applyArgs(params map (_.typeConstructor))))
+ else if (isHigherKinded) etaExpand
else super.normalize
)
+ override def etaExpand: Type = (
+ if (!isHigherKinded) this
+ else logResult("Normalizing HK $this")(typeFun(params, applyArgs(params map (_.typeConstructor))))
+ )
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 =>
@@ -3352,13 +3207,13 @@ trait Types extends api.Types { self: SymbolTable =>
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
+ private def levelString = if (settings.explaintypes) level else ""
override def safeToString = (
- if ((constr eq null) || (constr.inst eq null)) "TVar<" + originName + "=null>"
- else if (constr.inst ne NoType) "=?" + constr.inst
+ if ((constr eq null) || (inst eq null)) "TVar<" + originName + "=null>"
+ else if (inst ne NoType) "=?" + inst
else (if(untouchable) "!?" else "?") + levelString + originName
)
+ def originString = s"$originName in $originLocation"
override def kind = "TypeVar"
def cloneInternal = {
@@ -3376,13 +3231,9 @@ trait Types extends api.Types { self: SymbolTable =>
*
* @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)
+ override val underlying: Type)
extends RewrappingTypeProxy with AnnotatedTypeApi {
assert(!annotations.isEmpty, "" + underlying)
@@ -3415,9 +3266,6 @@ trait Types extends api.Types { self: SymbolTable =>
*/
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.
*/
@@ -3432,7 +3280,7 @@ trait Types extends api.Types { self: SymbolTable =>
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)
+ else AnnotatedType(annotations1, underlying1)
}
/** Return the base type sequence of tp, dropping the annotations, unless the base type sequence of tp
@@ -3451,12 +3299,19 @@ trait Types extends api.Types { self: SymbolTable =>
/** 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 =
+ def annotatedType(annots: List[AnnotationInfo], underlying: Type): Type =
if (annots.isEmpty) underlying
- else AnnotatedType(annots, underlying, selfsym)
+ else AnnotatedType(annots, underlying)
object AnnotatedType extends AnnotatedTypeExtractor
+ object StaticallyAnnotatedType {
+ def unapply(tp: Type): Option[(List[AnnotationInfo], Type)] = tp.staticAnnotations match {
+ case Nil => None
+ case annots => Some((annots, tp.withoutAnnotations))
+ }
+ }
+
/** A class representing types with a name. When an application uses
* named arguments, the named argument types for calling isApplicable
* are represented as NamedType.
@@ -3464,39 +3319,36 @@ trait Types extends api.Types { self: SymbolTable =>
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.
+ /** As with NamedType, used only when calling isApplicable.
+ * Records that the application has a wildcard star (aka _*)
+ * at the end of it.
*/
- 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+")"
- }
+ case class RepeatedType(tp: Type) extends Type {
+ override def safeToString: String = tp + ": _*"
}
/** A temporary type representing the erasure of a user-defined value type.
* Created during phase erasure, eliminated again in posterasure.
*
- * @param original The underlying type before erasure
+ * SI-6385 Erasure's creation of bridges considers method signatures `exitingErasure`,
+ * which contain `ErasedValueType`-s. In order to correctly consider the overriding
+ * and overriden signatures as equivalent in `run/t6385.scala`, it is critical that
+ * this type contains the erasure of the wrapped type, rather than the unerased type
+ * of the value class itself, as was originally done.
+ *
+ * @param valueClazz The value class symbol
+ * @param erasedUnderlying The erased type of the unboxed value
*/
- abstract case class ErasedValueType(original: TypeRef) extends UniqueType {
- override def safeToString = "ErasedValueType("+original+")"
+ abstract case class ErasedValueType(valueClazz: Symbol, erasedUnderlying: Type) extends UniqueType {
+ override def safeToString = s"ErasedValueType($valueClazz, $erasedUnderlying)"
}
- final class UniqueErasedValueType(original: TypeRef) extends ErasedValueType(original)
+ final class UniqueErasedValueType(valueClazz: Symbol, erasedUnderlying: Type) extends ErasedValueType(valueClazz, erasedUnderlying)
object ErasedValueType {
- def apply(original: TypeRef): Type = {
- assert(original.sym ne NoSymbol, "ErasedValueType over NoSymbol")
- unique(new UniqueErasedValueType(original))
+ def apply(valueClazz: Symbol, erasedUnderlying: Type): Type = {
+ assert(valueClazz ne NoSymbol, "ErasedValueType over NoSymbol")
+ unique(new UniqueErasedValueType(valueClazz, erasedUnderlying))
}
}
@@ -3524,17 +3376,19 @@ trait Types extends api.Types { self: SymbolTable =>
(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
+ else pre.nonPrivateMember(sym.name).suchThat { sym =>
+ // SI-7928 `isModuleNotMethod` is here to avoid crashing with spuriously "overloaded" module accessor and module symbols.
+ // These appear after refchecks eliminates ModuleDefs that implement an interface.
+ // Here, we exclude the module symbol, which allows us to bind to the accessor.
+ // SI-8054 We must only do this after refchecks, otherwise we exclude the module symbol which does not yet have an accessor!
+ val isModuleWithAccessor = phase.refChecked && sym.isModuleNotMethod
+ sym.isType || (!isModuleWithAccessor && sym.isStable && !sym.hasVolatileType)
+ } orElse sym
}
/** Convert a `super` prefix to a this-type if `sym` is abstract or final. */
@@ -3563,7 +3417,7 @@ trait Types extends api.Types { self: SymbolTable =>
/** 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
+ if (parents.isEmpty) ObjectTpe else parents.head
else {
val clazz = owner.newRefinementClass(pos)
val result = RefinedType(parents, decls, clazz)
@@ -3573,10 +3427,6 @@ trait Types extends api.Types { self: SymbolTable =>
}
/** 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)
@@ -3584,7 +3434,7 @@ trait Types extends api.Types { self: SymbolTable =>
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 owner = original.typeSymbol.owner
val result = refinedType(parents, owner)
val syms1 = decls.toList
for (sym <- syms1)
@@ -3685,7 +3535,7 @@ trait Types extends api.Types { self: SymbolTable =>
if (args.isEmpty)
return tycon //@M! `if (args.isEmpty) tycon' is crucial (otherwise we create new types in phases after typer and then they don't get adapted (??))
- /** Disabled - causes cycles in tcpoly tests. */
+ /* Disabled - causes cycles in tcpoly tests. */
if (false && isDefinitionsInitialized) {
assert(isUseableAsTypeArgs(args), {
val tapp_s = s"""$tycon[${args mkString ", "}]"""
@@ -3696,43 +3546,30 @@ trait Types extends api.Types { self: SymbolTable =>
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 TypeRef(pre, sym, Nil) => copyTypeRef(tycon, pre, sym, args)
+ case TypeRef(pre, sym, bogons) => devWarning(s"Dropping $bogons from $tycon in appliedType.") ; 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 RefinedType(parents, decls) => RefinedType(parents map (appliedType(_, args)), decls) // @PP: Can this be right?
+ case TypeBounds(lo, hi) => TypeBounds(appliedType(lo, args), appliedType(hi, args)) // @PP: Can this be right?
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 AnnotatedType(annots, underlying) => AnnotatedType(annots, appliedType(underlying, args))
+ case ErrorType | WildcardType => tycon
case _ => abort(debugString(tycon))
}
}
+ def appliedType(tycon: Type, args: Type*): Type =
+ appliedType(tycon, args.toList)
+
+ def appliedType(tyconSym: Symbol, args: List[Type]): Type =
+ appliedType(tyconSym.typeConstructor, args)
+
/** 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).
@@ -3759,7 +3596,7 @@ trait Types extends api.Types { self: SymbolTable =>
}
def genPolyType(params: List[Symbol], tpe: Type): Type = GenPolyType(params, tpe)
- @deprecated("use genPolyType(...) instead", "2.10.0")
+ @deprecated("use genPolyType(...) instead", "2.10.0") // Used in reflection API
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.
@@ -3806,131 +3643,7 @@ trait Types extends api.Types { self: SymbolTable =>
newExistentialType(tparams1, tpe1)
}
- /** Normalize any type aliases within this type (@see Type#normalize).
- * Note that this depends very much on the call to "normalize", not "dealias",
- * so it is no longer carries the too-stealthy name "deAlias".
- */
- object normalizeAliases extends TypeMap {
- def apply(tp: Type): Type = tp match {
- case TypeRef(_, sym, _) if sym.isAliasType =>
- def msg = if (tp.isHigherKinded) s"Normalizing type alias function $tp" else s"Dealiasing type alias $tp"
- mapOver(logResult(msg)(tp.normalize))
- case _ => mapOver(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) =>
- parents filter (_.typeSymbol != SingletonClass) match {
- case Nil => AnyClass.tpe
- case p :: Nil if decls.isEmpty => mapOver(p)
- case ps => mapOver(copyRefinedType(tp1, ps, 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
-
- /** Turn any T* types into Seq[T] except when
- * in method parameter position.
- */
- object dropRepeatedParamType extends TypeMap {
- def apply(tp: Type): Type = tp match {
- case MethodType(params, restpe) =>
- // Not mapping over params
- val restpe1 = apply(restpe)
- if (restpe eq restpe1) tp
- else MethodType(params, restpe1)
- 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 --------------------------------------------------------------
@@ -3942,7 +3655,11 @@ trait Types extends api.Types { self: SymbolTable =>
if (Statistics.canEnable) Statistics.incCounter(rawTypeCount)
if (uniqueRunId != currentRunId) {
uniques = util.WeakHashSet[Type](initialUniquesCapacity)
- perRunCaches.recordCache(uniques)
+ // JZ: We used to register this as a perRunCache so it would be cleared eagerly at
+ // the end of the compilation run. But, that facility didn't actually clear this map (SI-8129)!
+ // When i fixed that bug, run/tpeCache-tyconCache.scala started failing. Why was that?
+ // I've removed the registration for now. I don't think its particularly harmful anymore
+ // as a) this is now a weak set, and b) it is discarded completely before the next run.
uniqueRunId = currentRunId
}
(uniques findEntryOrUpdate tp).asInstanceOf[T]
@@ -3950,124 +3667,9 @@ trait Types extends api.Types { self: SymbolTable =>
// 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 typeIsNothing
- private var hibounds = hi0 filterNot typeIsAny
- 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) {
- // For some reason which is still a bit fuzzy, we must let Nothing through as
- // a lower bound despite the fact that Nothing is always a lower bound. My current
- // supposition is that the side-effecting type constraint accumulation mechanism
- // depends on these subtype tests being performed to make forward progress when
- // there are mutally recursive type vars.
- // See pos/t6367 and pos/t6499 for the competing test cases.
- val mustConsider = tp.typeSymbol match {
- case NothingClass => true
- case _ => !(lobounds contains tp)
- }
- if (mustConsider) {
- 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) {
- // My current test case only demonstrates the need to let Nothing through as
- // a lower bound, but I suspect the situation is symmetrical.
- val mustConsider = tp.typeSymbol match {
- case AnyClass => true
- case _ => !(hibounds contains tp)
- }
- if (mustConsider) {
- 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 typeIsNothing
- val hi = hiBounds filterNot typeIsAny
- 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 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)
@@ -4075,309 +3677,69 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
class ClassUnwrapper(existential: Boolean) extends TypeUnwrapper(poly = true, existential, annotated = true, nullary = false) {
- override def apply(tp: Type) = super.apply(tp.normalize)
+ override def apply(tp: Type) = super.apply(tp.normalize) // normalize is required here
}
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]) =
- //OPT inline from forall to save on #closures
- origSyms match {
- case sym :: rest =>
- val v = variance
- if (sym.isAliasType) variance = 0
- val result = this(sym.info)
- variance = v
- (result eq sym.info) && noChangeToSymbols(rest)
- case _ =>
- true
- }
-
- 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)
+ def elementExtract(container: Symbol, tp: Type): Type = {
+ assert(!container.isAliasType, container)
+ unwrapWrapperTypes(tp baseType container).dealiasWiden match {
+ case TypeRef(_, `container`, arg :: Nil) => arg
+ case _ => NoType
}
}
-
- // 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: _*)
+ def elementExtractOption(container: Symbol, tp: Type): Option[Type] = {
+ elementExtract(container, tp) match {
+ case NoType => None
+ case tp => Some(tp)
}
-
- /** 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 elementTest(container: Symbol, tp: Type)(f: Type => Boolean): Boolean = {
+ elementExtract(container, tp) match {
+ case NoType => false
+ case tp => f(tp)
}
-
- def mapOverAnnotations(annots: List[AnnotationInfo]): List[AnnotationInfo] = {
- val annots1 = annots mapConserve mapOver
- if (annots1 eq annots) annots
- else annots1 filterNot (_ eq UnmappableAnnotation)
+ }
+ def elementTransform(container: Symbol, tp: Type)(f: Type => Type): Type = {
+ elementExtract(container, tp) match {
+ case NoType => NoType
+ case tp => f(tp)
}
+ }
- /** 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)
- }
+ def transparentShallowTransform(container: Symbol, tp: Type)(f: Type => Type): Type = {
+ def loop(tp: Type): Type = tp match {
+ case tp @ AnnotatedType(_, underlying) => tp.copy(underlying = loop(underlying))
+ case tp @ ExistentialType(_, underlying) => tp.copy(underlying = loop(underlying))
+ case tp @ PolyType(_, resultType) => tp.copy(resultType = loop(resultType))
+ case tp @ NullaryMethodType(resultType) => tp.copy(resultType = loop(resultType))
+ case tp => elementTransform(container, tp)(el => appliedType(container, f(el))).orElse(f(tp))
}
+ loop(tp)
}
- abstract class TypeTraverser extends TypeMap {
- def traverse(tp: Type): Unit
- def apply(tp: Type): Type = { traverse(tp); tp }
- }
+ /** 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)
+ )
- abstract class TypeTraverserWithResult[T] extends TypeTraverser {
- def result: T
- def clear(): Unit
- }
+ def containsExistential(tpe: Type) = tpe exists typeIsExistentiallyBound
+ def existentialsInType(tpe: Type) = tpe withFilter typeIsExistentiallyBound map (_.typeSymbol)
- abstract class TypeCollector[T](initial: T) extends TypeTraverser {
- var result: T = _
- def collect(tp: Type) = {
- result = initial
- traverse(tp)
- result
- }
+ private def isDummyOf(tpe: Type)(targ: Type) = {
+ val sym = targ.typeSymbol
+ sym.isTypeParameter && sym.owner == tpe.typeSymbol
+ }
+ def isDummyAppliedType(tp: Type) = tp.dealias match {
+ case tr @ TypeRef(_, _, args) => args exists isDummyOf(tr)
+ case _ => false
}
-
- /** 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) =>
@@ -4388,630 +3750,23 @@ trait Types extends api.Types { self: SymbolTable =>
def typeParamsToExistentials(clazz: Symbol): List[Symbol] =
typeParamsToExistentials(clazz, clazz.typeParams)
+ def isRawIfWithoutArgs(sym: Symbol) = sym.isClass && sym.typeParams.nonEmpty && sym.isJavaDefined
+ /** Is type tp a ''raw type''? */
// 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)))
-
- /** Might the given symbol be important when calculating the prefix
- * of a type? When tp.asSeenFrom(pre, clazz) is called on `tp`,
- * the result will be `tp` unchanged if `pre` is trivial and `clazz`
- * is a symbol such that isPossiblePrefix(clazz) == false.
- */
- def isPossiblePrefix(clazz: Symbol) = clazz.isClass && !clazz.isPackageClass
+ def isRawType(tp: Type) = !phase.erasedTypes && (tp match {
+ case TypeRef(_, sym, Nil) => isRawIfWithoutArgs(sym)
+ case _ => false
+ })
- private def skipPrefixOf(pre: Type, clazz: Symbol) = (
- (pre eq NoType) || (pre eq NoPrefix) || !isPossiblePrefix(clazz)
+ @deprecated("Use isRawType", "2.10.1") // presently used by sbt
+ def isRaw(sym: Symbol, args: List[Type]) = (
+ !phase.erasedTypes
+ && args.isEmpty
+ && isRawIfWithoutArgs(sym)
)
- /** 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()
-
- override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = {
- object annotationArgRewriter extends TypeMapTransformer {
- private def canRewriteThis(sym: Symbol) = (
- (sym isNonBottomSubClass clazz)
- && (pre.widen.typeSymbol isNonBottomSubClass sym)
- && (pre.isStable || giveup())
- )
- // what symbol should really be used?
- private def newTermSym() = {
- val p = pre.typeSymbol
- p.owner.newValue(p.name.toTermName, p.pos) setInfo pre
- }
- /** Rewrite `This` trees in annotation argument trees */
- override def transform(tree: Tree): Tree = super.transform(tree) match {
- case This(_) if canRewriteThis(tree.symbol) => gen.mkAttributedQualifier(pre, newTermSym())
- case tree => tree
- }
- }
- annotationArgRewriter.transform(tree)
- }
-
- def stabilize(pre: Type, clazz: Symbol): Type = {
- capturedParams find (_.owner == clazz) match {
- case Some(qvar) => qvar.tpe
- case _ =>
- val qvar = clazz freshExistential nme.SINGLETON_SUFFIX setInfo singletonBounds(pre)
- capturedParams ::= qvar
- qvar.tpe
- }
- }
-
- def apply(tp: Type): Type =
- tp match {
- case ThisType(sym) =>
- def toPrefix(pre: Type, clazz: Symbol): Type =
- if (skipPrefixOf(pre, clazz)) 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(pre.baseType(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 (skipPrefixOf(pre, clazz)) 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 typeIsErroneous)
- 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(pre.baseType(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.nonEmpty && (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) {
- def this(pairs: (Symbol, Symbol)*) = this(pairs.toList.map(_._1), pairs.toList.map(_._2))
-
- 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)
- // mapOver takes care of subst'ing in args
- mapOver ( if (sym eq newSym) tp else copyTypeRef(tp, pre, newSym, args) )
- // assert(newSym.typeParams.length == sym.typeParams.length, "typars mismatch in SubstSymMap: "+(sym, sym.typeParams, newSym, newSym.typeParams))
- case SingleType(pre, sym) if pre ne NoPrefix =>
- val newSym = subst(sym, from, to)
- mapOver( if (sym eq newSym) tp else singleType(pre, newSym) )
- case _ =>
- super.apply(tp)
- }
- }
-
- object mapTreeSymbols extends TypeMapTransformer {
- val strictCopy = newStrictTreeCopier
-
- def termMapsTo(sym: Symbol) = from indexOf sym match {
- case -1 => None
- case idx => Some(to(idx))
- }
-
- // if tree.symbol is mapped to another symbol, passes the new symbol into the
- // constructor `trans` and sets the symbol and the type on the resulting tree.
- def transformIfMapped(tree: Tree)(trans: Symbol => Tree) = termMapsTo(tree.symbol) match {
- case Some(toSym) => trans(toSym) setSymbol toSym setType tree.tpe
- case None => tree
- }
-
- // changes trees which refer to one of the mapped symbols. trees are copied before attributes are modified.
- override def transform(tree: Tree) = {
- // super.transform maps symbol references in the types of `tree`. it also copies trees where necessary.
- super.transform(tree) match {
- case id @ Ident(_) =>
- transformIfMapped(id)(toSym =>
- strictCopy.Ident(id, toSym.name))
-
- case sel @ Select(qual, name) =>
- transformIfMapped(sel)(toSym =>
- strictCopy.Select(sel, qual, toSym.name))
-
- case tree => tree
- }
- }
- }
- override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = {
- mapTreeSymbols.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.dealias)
- }
- }
-
- object ApproximateDependentMap extends TypeMap {
- def apply(tp: Type): Type =
- if (tp.isImmediatelyDependent) WildcardType
- else mapOver(tp)
- }
-
- /** Note: This map is needed even for non-dependent method types, despite what the name might imply.
- */
- 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(param.name.toTypeName append nme.SINGLETON_SUFFIX, 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)
- }
- }
- }
+ def singletonBounds(hi: Type) = TypeBounds.upper(intersectionType(List(hi, SingletonClass.tpe)))
/**
* A more persistent version of `Type#memberType` which does not require
@@ -5059,194 +3814,15 @@ trait Types extends api.Types { self: SymbolTable =>
result
}
- /** 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
- }
- }
-
- final case class SubTypePair(tp1: Type, tp2: Type) {
- // SI-8146 we used to implement equality here in terms of pairwise =:=.
- // But, this was inconsistent with hashCode, which was based on the
- // Type#hashCode, based on the structure of types, not the meaning.
- // Now, we use `Type#{equals,hashCode}` as the (consistent) basis for
- // detecting cycles (aka keeping subtyping decidable.)
- //
- // I added tests to show that we detect the cycle: neg/t8146-no-finitary*
-
- override def toString = tp1+" <:<? "+tp2
- }
-
// Helper Methods -------------------------------------------------------------
/** The maximum allowable depth of lubs or glbs over types `ts`.
*/
- def lubDepth(ts: List[Type]): Int = {
+ def lubDepth(ts: List[Type]): Depth = {
val td = typeDepth(ts)
val bd = baseTypeSeqDepth(ts)
lubDepthAdjust(td, td max bd)
@@ -5256,48 +3832,17 @@ trait Types extends api.Types { self: SymbolTable =>
* as a function over the maximum depth `td` of these types, and
* the maximum depth `bd` of all types in the base type sequences of these types.
*/
- private def lubDepthAdjust(td: Int, bd: Int): Int =
- if (settings.XfullLubs.value) bd
- else if (bd <= 3) bd
- else if (bd <= 5) td max (bd - 1)
- else if (bd <= 7) td max (bd - 2)
- else (td - 1) max (bd - 3)
-
- /** The maximum depth of type `tp` */
- def typeDepth(tp: Type): Int = tp match {
- case TypeRef(pre, sym, args) =>
- typeDepth(pre) max typeDepth(args) + 1
- case RefinedType(parents, decls) =>
- typeDepth(parents) max typeDepth(decls.toList.map(_.info)) + 1
- case TypeBounds(lo, hi) =>
- typeDepth(lo) max typeDepth(hi)
- case MethodType(paramtypes, result) =>
- typeDepth(result)
- case NullaryMethodType(result) =>
- typeDepth(result)
- case PolyType(tparams, result) =>
- typeDepth(result) max typeDepth(tparams map (_.info)) + 1
- case ExistentialType(tparams, result) =>
- typeDepth(result) max typeDepth(tparams map (_.info)) + 1
- case _ =>
- 1
- }
-
- private def maxDepth(tps: List[Type], by: Type => Int): Int = {
- //OPT replaced with tailrecursive function to save on #closures
- // was:
- // var d = 0
- // for (tp <- tps) d = d max by(tp) //!!!OPT!!!
- // d
- def loop(tps: List[Type], acc: Int): Int = tps match {
- case tp :: rest => loop(rest, acc max by(tp))
- case _ => acc
- }
- loop(tps, 0)
- }
+ private def lubDepthAdjust(td: Depth, bd: Depth): Depth = (
+ if (settings.XfullLubs) bd
+ else if (bd <= Depth(3)) bd
+ else if (bd <= Depth(5)) td max bd.decr
+ else if (bd <= Depth(7)) td max (bd decr 2)
+ else td.decr max (bd decr 3)
+ )
- private def typeDepth(tps: List[Type]): Int = maxDepth(tps, typeDepth)
- private def baseTypeSeqDepth(tps: List[Type]): Int = maxDepth(tps, _.baseTypeSeqDepth)
+ private def symTypeDepth(syms: List[Symbol]): Depth = typeDepth(syms map (_.info))
+ private def typeDepth(tps: List[Type]): Depth = maxDepth(tps)
+ private def baseTypeSeqDepth(tps: List[Type]): Depth = maxbaseTypeSeqDepth(tps)
/** Is intersection of given types populated? That is,
* for all types tp1, tp2 in intersection
@@ -5310,32 +3855,35 @@ trait Types extends api.Types { self: SymbolTable =>
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
- }
+ assert(sym1 == sym2, (sym1, sym2))
+ ( pre1 =:= pre2
+ && forall3(args1, args2, sym1.typeParams) { (arg1, arg2, tparam) =>
+ // 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.isInvariant)
+ arg1 =:= arg2
+ else !arg1.isInstanceOf[TypeVar] || {
+ if (tparam.variance.isContravariant) arg1 <:< arg2
+ else arg2 <:< arg1
+ }
+ }
+ )
case (et: ExistentialType, _) =>
et.withTypeVars(isConsistent(_, tp2))
case (_, et: ExistentialType) =>
et.withTypeVars(isConsistent(tp1, _))
}
- def check(tp1: Type, tp2: Type) =
+ 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.
+ check(tp1, tp2) && check(tp2, tp1)
}
/** Does a pattern of type `patType` need an outer test when executed against
@@ -5378,85 +3926,14 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
- 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 || sym1.owner.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 {
- if (Statistics.canEnable) Statistics.incCounter(sametypeCount)
- subsametypeRecursions += 1
- //OPT cutdown on Function0 allocation
- //was:
-// undoLog undoUnless {
-// isSameType1(tp1, tp2)
-// }
-
- undoLog.lock()
- try {
- val before = undoLog.log
- var result = false
-
- try result = {
- isSameType1(tp1, tp2)
- } finally if (!result) undoLog.undoTo(before)
- result
- } finally undoLog.unlock()
- } 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) =
+ def normalizePlus(tp: Type) = (
if (isRawType(tp)) rawToExistential(tp)
- else tp.normalize
+ else tp.normalize match {
+ // Unify the two representations of module classes
+ case st @ SingleType(_, sym) if sym.isModule => st.underlying.normalize
+ case _ => tp.normalize
+ }
+ )
/*
todo: change to:
@@ -5468,288 +3945,7 @@ trait Types extends api.Types { self: SymbolTable =>
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 =>
- 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)(_ =:= _)
@@ -5767,103 +3963,49 @@ trait Types extends api.Types { self: SymbolTable =>
*/
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
-
- //OPT cutdown on Function0 allocation
- //was:
-// 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)
-// }
-// }
-
- undoLog.lock()
- try {
- val before = undoLog.log
- var result = false
-
- try result = { // if subtype test fails, it should not affect constraints on typevars
- if (subsametypeRecursions >= LogPendingSubTypesThreshold) {
- val p = new SubTypePair(tp1, tp2)
- if (pendingSubTypes(p))
- false // see neg/t8146-no-finitary*
- else
- try {
- pendingSubTypes += p
- isSubType2(tp1, tp2, depth)
- } finally {
- pendingSubTypes -= p
- }
- } else {
- isSubType2(tp1, tp2, depth)
- }
- } finally if (!result) undoLog.undoTo(before)
+ private var _basetypeRecursions: Int = 0
+ def basetypeRecursions = _basetypeRecursions
+ def basetypeRecursions_=(value: Int) = _basetypeRecursions = value
- result
- } finally undoLog.unlock()
- } 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()
- }
+ private val _pendingBaseTypes = new mutable.HashSet[Type]
+ def pendingBaseTypes = _pendingBaseTypes
/** Does this type have a prefix that begins with a type variable,
* or is it a refinement type? For type prefixes that fulfil this condition,
* type selections with the same name of equal (as determined by `=:=`) prefixes are
* considered equal in regard to `=:=`.
*/
- 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
- }
-
- @deprecated("The compiler doesn't use this so you shouldn't either - it will be removed", "2.10.0")
- 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 isEligibleForPrefixUnification(tp: Type): Boolean = tp match {
+ case SingleType(pre, sym) => !(sym hasFlag PACKAGE) && isEligibleForPrefixUnification(pre)
+ case tv@TypeVar(_, constr) => !tv.instValid || isEligibleForPrefixUnification(constr.inst)
+ case RefinedType(_, _) => true
+ case _ => false
}
def isErrorOrWildcard(tp: Type) = (tp eq ErrorType) || (tp eq WildcardType)
+ /** This appears to be equivalent to tp.isInstanceof[SingletonType],
+ * except it excludes ConstantTypes.
+ */
def isSingleType(tp: Type) = tp match {
case ThisType(_) | SuperType(_, _) | SingleType(_, _) => true
- case _ => false
+ case _ => false
}
def isConstantType(tp: Type) = tp match {
case ConstantType(_) => true
- case _ => false
+ case _ => false
+ }
+
+ def isExistentialType(tp: Type): Boolean = tp match {
+ case _: ExistentialType => true
+ case tp: Type if tp.dealias ne tp => isExistentialType(tp.dealias)
+ case _ => false
+ }
+
+ def isImplicitMethodType(tp: Type) = tp match {
+ case mt: MethodType => mt.isImplicit
+ case _ => false
}
/** This is defined and named as it is because the goal is to exclude source
@@ -5891,10 +4033,11 @@ trait Types extends api.Types { self: SymbolTable =>
* types which are used internally in type applications and
* types which are not.
*/
+ /**** Not used right now, but kept around to document which Types
+ * land in which bucket.
private def isInternalTypeNotUsedAsTypeArg(tp: Type): Boolean = tp match {
case AntiPolyType(pre, targs) => true
case ClassInfoType(parents, defs, clazz) => true
- case DeBruijnIndex(level, index, args) => true
case ErasedValueType(tref) => true
case NoPrefix => true
case NoType => true
@@ -5902,6 +4045,7 @@ trait Types extends api.Types { self: SymbolTable =>
case TypeBounds(lo, hi) => true
case _ => false
}
+ ****/
private def isInternalTypeUsedAsTypeArg(tp: Type): Boolean = tp match {
case WildcardType => true
case BoundedWildcardType(_) => true
@@ -5929,7 +4073,7 @@ trait Types extends api.Types { self: SymbolTable =>
private def isValueElseNonValue(tp: Type): Boolean = tp match {
case tp if isAlwaysValueType(tp) => true
case tp if isAlwaysNonValueType(tp) => false
- case AnnotatedType(_, underlying, _) => isValueElseNonValue(underlying)
+ case AnnotatedType(_, underlying) => isValueElseNonValue(underlying)
case SingleType(_, sym) => sym.isValue // excludes packages and statics
case TypeRef(_, _, _) if tp.isHigherKinded => false // excludes type constructors
case ThisType(sym) => !sym.isPackageClass // excludes packages
@@ -5947,7 +4091,7 @@ trait Types extends api.Types { self: SymbolTable =>
* useful as documentation; it is likely that !isNonValueType(tp)
* will serve better than isValueType(tp).
*/
- def isValueType(tp: Type) = isValueElseNonValue(tp)
+ /** def isValueType(tp: Type) = isValueElseNonValue(tp) */
/** SLS 3.3, Non-Value Types
* Is the given type definitely a non-value type, as defined in SLS 3.3?
@@ -5958,7 +4102,7 @@ trait Types extends api.Types { self: SymbolTable =>
* not designated non-value types because there is code which depends on using
* them as type arguments, but their precise status is unclear.
*/
- def isNonValueType(tp: Type) = !isValueElseNonValue(tp)
+ /** def isNonValueType(tp: Type) = !isValueElseNonValue(tp) */
def isNonRefinementClassType(tpe: Type) = tpe match {
case SingleType(_, sym) => sym.isModuleClass
@@ -5967,294 +4111,70 @@ trait Types extends api.Types { self: SymbolTable =>
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 isSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[Symbol], depth: Int): Boolean = {
- def isSubArg(t1: Type, t2: Type, variance: Int) =
- (variance > 0 || isSubType(t2, t1, depth)) &&
- (variance < 0 || isSubType(t1, t2, depth))
- 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 || sym1.owner.hasPackageFlag || isSubType(pre1, pre2, depth)
- 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, depth))
- ||
- sym2.isClass && {
- val base = tr1 baseType sym2
- (base ne tr1) && isSubType(base, tr2, depth)
- }
- ||
- thirdTryRef(tr1, tr2))
- case _ =>
- secondTry
- }
- case AnnotatedType(_, _, _) =>
- isSubType(tp1.withoutAnnotations, tp2.withoutAnnotations, depth) &&
- annotationsConform(tp1, tp2)
- case BoundedWildcardType(bounds) =>
- isSubType(tp1, bounds.hi, depth)
- 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(_, _, _) =>
- isSubType(tp1.withoutAnnotations, tp2.withoutAnnotations, depth) &&
- annotationsConform(tp1, tp2)
- case BoundedWildcardType(bounds) =>
- isSubType(tp1.bounds.lo, tp2, depth)
- case tv @ TypeVar(_,_) =>
- tv.registerBound(tp2, false)
- case ExistentialType(_, _) =>
- try {
- skolemizationLevel += 1
- isSubType(tp1.skolemizeExistential, tp2, depth)
- } 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) &&
- isSubType(tp1, tp2a, depth) ||
- fourthTry
- } else {
- isSubType(tp1.normalize, tp2.normalize, depth)
- }
- case _ =>
- fourthTry
- }
- }
+ def isSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[Symbol], depth: Depth): Boolean = {
+ def isSubArg(t1: Type, t2: Type, variance: Variance) = (
+ (variance.isCovariant || isSubType(t2, t1, depth)) // The order of these two checks can be material for performance (SI-8478)
+ && (variance.isContravariant || isSubType(t1, t2, depth))
+ )
- /** 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 (isSubType(tp1, _, depth))) &&
- (rt2.decls forall (specializesSym(tp1, _, depth)))
- case et2: ExistentialType =>
- et2.withTypeVars(isSubType(tp1, _, depth), depth) || fourthTry
- case nn2: NotNullType =>
- tp1.isNotNull && isSubType(tp1, nn2.underlying, depth)
- 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) &&
- isSubType(res1.substSym(params1, params2), res2, depth))
- // 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(_) =>
- isSubType(pt1.resultType, pt2.resultType, depth)
- case _ =>
- false
- }
- case TypeBounds(lo2, hi2) =>
- tp1 match {
- case TypeBounds(lo1, hi1) =>
- isSubType(lo2, lo1, depth) && isSubType(hi1, hi2, depth)
- case _ =>
- false
- }
- case _ =>
- fourthTry
- }
+ corresponds3(tps1, tps2, mapList(tparams)(_.variance))(isSubArg)
+ }
- /** 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) && isSubType(tp1, tp2.widen, depth)
- }
- 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) && isSubType(tp1a, tp2, depth)
- } else {
- isSubType(tp1.normalize, tp2.normalize, depth)
- }
- case _ =>
- false
- }
- case RefinedType(parents1, _) =>
- parents1 exists (isSubType(_, tp2, depth))
- case _: SingletonType | _: NotNullType =>
- isSubType(tp1.underlying, tp2, depth)
- case _ =>
- false
- }
+ def specializesSym(tp: Type, sym: Symbol, depth: Depth): Boolean = {
+ def directlySpecializedBy(member: Symbol): Boolean = (
+ member == sym
+ || specializesSym(tp.narrow, member, sym.owner.thisType, sym, depth)
+ )
+ // Closure reduction, else this would be simply `member exists directlySpecializedBy`
+ def specializedBy(member: Symbol): Boolean = (
+ if (member eq NoSymbol) false
+ else if (member.isOverloaded) member.alternatives exists directlySpecializedBy
+ else directlySpecializedBy(member)
+ )
- firstTry
+ ( (tp.typeSymbol isBottomSubClass sym.owner)
+ || specializedBy(tp nonPrivateMember sym.name)
+ )
}
- 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`?
+ /** Does member `symLo` of `tpLo` have a stronger type
+ * than member `symHi` of `tpHi`?
*/
- def isSubTypes(tps1: List[Type], tps2: List[Type]): Boolean = (tps1 corresponds tps2)(_ <:< _)
+ protected[internal] def specializesSym(preLo: Type, symLo: Symbol, preHi: Type, symHi: Symbol, depth: Depth): Boolean =
+ (symHi.isAliasType || symHi.isTerm || symHi.isAbstractType) && {
+ // only now that we know symHi is a viable candidate ^^^^^^^, do the expensive checks: ----V
+ require((symLo ne NoSymbol) && (symHi ne NoSymbol), ((preLo, symLo, preHi, symHi, depth)))
+
+ val tpHi = preHi.memberInfo(symHi).substThis(preHi.typeSymbol, preLo)
+
+ // Should we use memberType or memberInfo?
+ // memberType transforms (using `asSeenFrom`) `sym.tpe`,
+ // whereas memberInfo performs the same transform on `sym.info`.
+ // For term symbols, this ends up being the same thing (`sym.tpe == sym.info`).
+ // For type symbols, however, the `.info` of an abstract type member
+ // is defined by its bounds, whereas its `.tpe` is a `TypeRef` to that type symbol,
+ // so that `sym.tpe <:< sym.info`, but not the other way around.
+ //
+ // Thus, for the strongest (correct) result,
+ // we should use `memberType` on the low side.
+ //
+ // On the high side, we should use the result appropriate
+ // for the right side of the `<:<` above (`memberInfo`).
+ val tpLo = preLo.memberType(symLo)
- /** 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 =
- specializesSym(tp, sym, AnyDepth)
-
- def specializesSym(tp: Type, sym: Symbol, depth: Int): Boolean =
- tp.typeSymbol == NothingClass ||
- tp.typeSymbol == NullClass && containsNull(sym.owner) || {
- def specializedBy(membr: Symbol): Boolean =
- membr == sym || specializesSym(tp.narrow, membr, sym.owner.thisType, sym, depth)
- val member = tp.nonPrivateMember(sym.name)
- if (member eq NoSymbol) false
- else if (member.isOverloaded) member.alternatives exists specializedBy
- else specializedBy(member)
- // was
- // (tp.nonPrivateMember(sym.name).alternatives exists
- // (alt => sym == alt || specializesSym(tp.narrow, alt, sym.owner.thisType, sym, depth)))
- }
+ debuglog(s"specializesSymHi: $preHi . $symHi : $tpHi")
+ debuglog(s"specializesSymLo: $preLo . $symLo : $tpLo")
- /** 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, depth: Int): 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 && isSubType(info1, info2, depth) && (!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
- )
- }
+ if (symHi.isTerm)
+ (isSubType(tpLo, tpHi, depth) &&
+ (!symHi.isStable || symLo.isStable) && // sub-member must remain stable
+ (!symLo.hasVolatileType || symHi.hasVolatileType || tpHi.isWildcard)) // sub-member must not introduce volatility
+ else if (symHi.isAbstractType)
+ ((tpHi.bounds containsType tpLo) &&
+ kindsConform(symHi :: Nil, tpLo :: Nil, preLo, symLo.owner))
+ else // we know `symHi.isAliasType` (see above)
+ tpLo =:= tpHi
+ }
/** A function implementing `tp1` matches `tp2`. */
final def matchesType(tp1: Type, tp2: Type, alwaysMatchSimple: Boolean): Boolean = {
@@ -6265,7 +4185,7 @@ trait Types extends api.Types { self: SymbolTable =>
def lastTry =
tp2 match {
case ExistentialType(_, res2) if alwaysMatchSimple =>
- matchesType(tp1, res2, true)
+ matchesType(tp1, res2, alwaysMatchSimple = true)
case MethodType(_, _) =>
false
case PolyType(_, _) =>
@@ -6285,7 +4205,7 @@ trait Types extends api.Types { self: SymbolTable =>
if (params1.isEmpty) matchesType(res1, res2, alwaysMatchSimple)
else matchesType(tp1, res2, alwaysMatchSimple)
case ExistentialType(_, res2) =>
- alwaysMatchSimple && matchesType(tp1, res2, true)
+ alwaysMatchSimple && matchesType(tp1, res2, alwaysMatchSimple = true)
case TypeRef(_, sym, Nil) =>
params1.isEmpty && sym.isModuleClass && matchesType(res1, tp2, alwaysMatchSimple)
case _ =>
@@ -6298,7 +4218,7 @@ trait Types extends api.Types { self: SymbolTable =>
case NullaryMethodType(res2) =>
matchesType(res1, res2, alwaysMatchSimple)
case ExistentialType(_, res2) =>
- alwaysMatchSimple && matchesType(tp1, res2, true)
+ alwaysMatchSimple && matchesType(tp1, res2, alwaysMatchSimple = true)
case TypeRef(_, sym, Nil) if sym.isModuleClass =>
matchesType(res1, tp2, alwaysMatchSimple)
case _ =>
@@ -6312,7 +4232,7 @@ trait Types extends api.Types { self: SymbolTable =>
else
matchesQuantified(tparams1, tparams2, res1, res2)
case ExistentialType(_, res2) =>
- alwaysMatchSimple && matchesType(tp1, res2, true)
+ alwaysMatchSimple && matchesType(tp1, res2, alwaysMatchSimple = true)
case _ =>
false // remember that tparams1.nonEmpty is now an invariant of PolyType
}
@@ -6321,7 +4241,7 @@ trait Types extends api.Types { self: SymbolTable =>
case ExistentialType(tparams2, res2) =>
matchesQuantified(tparams1, tparams2, res1, res2)
case _ =>
- if (alwaysMatchSimple) matchesType(res1, tp2, true)
+ if (alwaysMatchSimple) matchesType(res1, tp2, alwaysMatchSimple = true)
else lastTry
}
case TypeRef(_, sym, Nil) if sym.isModuleClass =>
@@ -6374,7 +4294,7 @@ trait Types extends api.Types { self: SymbolTable =>
*/
/** 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 {
+ protected[internal] def matchingParams(syms1: List[Symbol], syms2: List[Symbol], syms1isJava: Boolean, syms2isJava: Boolean): Boolean = syms1 match {
case Nil =>
syms2.isEmpty
case sym1 :: rest1 =>
@@ -6391,99 +4311,6 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
- /** 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) {
- log(s"$tvar addHiBound $bound.instantiateTypeParams($tparams, $tvars)")
- tvar addHiBound bound.instantiateTypeParams(tparams, tvars)
- }
- for (tparam2 <- tparams)
- tparam2.info.bounds.lo.dealias match {
- case TypeRef(_, `tparam`, _) =>
- log(s"$tvar addHiBound $tparam2.tpeHK.instantiateTypeParams($tparams, $tvars)")
- tvar addHiBound tparam2.tpeHK.instantiateTypeParams(tparams, tvars)
- case _ =>
- }
- } else {
- if (bound.typeSymbol != NothingClass && bound.typeSymbol != tparam) {
- log(s"$tvar addLoBound $bound.instantiateTypeParams($tparams, $tvars)")
- tvar addLoBound bound.instantiateTypeParams(tparams, tvars)
- }
- for (tparam2 <- tparams)
- tparam2.info.bounds.hi.dealias match {
- case TypeRef(_, `tparam`, _) =>
- log(s"$tvar addLoBound $tparam2.tpeHK.instantiateTypeParams($tparams, $tvars)")
- 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)))
- val newInst = (
- 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)
- }
- )
- log(s"$tvar setInst $newInst")
- tvar setInst newInst
- //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 = {
@@ -6494,167 +4321,7 @@ trait Types extends api.Types { self: SymbolTable =>
}
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 typeListIsEmpty)) 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 regarding 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 of a list of types (as determined by `Symbol.isLess`). */
- 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 List(t) => List(t)
- case t :: ts1 =>
- val rest = elimSuper(ts1 filter (t1 => !(t <:< t1)))
- if (rest exists (t1 => t1 <:< t)) rest else t :: rest
- }
+ mapList(tparams)(_.info.asSeenFrom(pre, owner).instantiateTypeParams(tparams, targs).bounds)
def elimAnonymousClass(t: Type) = t match {
case TypeRef(pre, clazz, Nil) if clazz.isAnonymousClass =>
@@ -6662,397 +4329,6 @@ trait Types extends api.Types { self: SymbolTable =>
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 List(t) => List(t)
- 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.dealiasWiden))
- 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): Type = tp match {
- case ExistentialType(_, res) =>
- res
- case tv@TypeVar(_, constr) =>
- if (tv.instValid) stripType(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 exists typeHasAnnotations)
- (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 exists typeHasAnnotations) {
- (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): Boolean = (
- 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 _ =>
- if (Statistics.canEnable) Statistics.incCounter(lubCount)
- val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, lubNanos) else null
- try {
- lub(ts, lubDepth(ts))
- } finally {
- lubResults.clear()
- glbResults.clear()
- if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
- }
- }
-
- /** 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 @ (mt @ MethodType(params, _)) :: rest =>
- MethodType(params, lub0(matchingRestypes(ts, mt.paramTypes)))
- 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 @ AnnotatedType(annots, tpe, _) :: rest =>
- annotationsLub(lub0(ts map (_.withoutAnnotations)), ts)
- 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, depth)))
- }
- // 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, depth)
- } 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 =>
- isSubType(t, lubRefined, depth) || {
- 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
- }
- }
- // dropRepeatedParamType is a localized fix for SI-6897. We should probably
- // integrate that transformation at a lower level in master, but lubs are
- // the likely and maybe only spot they escape, so fixing here for 2.10.1.
- existentialAbstraction(tparams, dropRepeatedParamType(lubType))
- }
- if (printLubs) {
- println(indent + "lub of " + ts + " at depth "+depth)//debug
- indent = indent + " "
- assert(indent.length <= 100)
- }
- if (Statistics.canEnable) Statistics.incCounter(nestedLubCount)
- val res = lub0(ts)
- if (printLubs) {
- indent = indent stripSuffix " "
- println(indent + "lub of " + ts + " is " + res)//debug
- }
- if (ts forall typeIsNotNull) 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 of a list of types (as determined by `<:<`). */
- def glb(ts: List[Type]): Type = elimSuper(ts) match {
- case List() => AnyClass.tpe
- case List(t) => t
- case ts0 =>
- if (Statistics.canEnable) Statistics.incCounter(lubCount)
- val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, lubNanos) else null
- try {
- glbNorm(ts0, lubDepth(ts0))
- } finally {
- lubResults.clear()
- glbResults.clear()
- if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
- }
- }
-
- 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 of a list of types (as determined by `<:<`), which have been normalized
- * with regard to `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 @ (mt @ MethodType(params, _)) :: rest =>
- MethodType(params, glbNorm(matchingRestypes(ts, mt.paramTypes), 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 && !specializesSym(glbThisType, sym, depth))
- try {
- addMember(glbThisType, glbRefined, glbsym(sym), depth)
- } 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
-
- if (Statistics.canEnable) Statistics.incCounter(nestedLubCount)
- 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 typeIsNotNull) res.notNull else res
- }
/** A list of the typevars in a type. */
def typeVarsInType(tp: Type): List[TypeVar] = {
@@ -7063,29 +4339,32 @@ trait Types extends api.Types { self: SymbolTable =>
}
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...
+
+ // 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 pos/t0851 for a situation where this happens.
+ @inline final def suspendingTypeVars[T](tvs: List[TypeVar])(op: => T): T = {
+ val saved = tvs map (_.suspended)
tvs foreach (_.suspended = true)
- tvs
+
+ try op
+ finally foreach2(tvs, saved)(_.suspended = _)
}
- /** Compute lub (if `variance == 1`) or glb (if `variance == -1`) of given list
+ /** Compute lub (if `variance == Covariant`) or glb (if `variance == Contravariant`) 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.
+ * Return `x` if the computation succeeds with result `x`.
+ * Return `NoType` if the computation fails.
*/
- def mergePrefixAndArgs(tps: List[Type], variance: Int, depth: Int): Option[Type] = tps match {
- case List(tp) =>
- Some(tp)
+ def mergePrefixAndArgs(tps: List[Type], variance: Variance, depth: Depth): Type = tps match {
+ case tp :: Nil => 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 pre = if (variance.isPositive) 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 {
@@ -7094,12 +4373,13 @@ trait Types extends api.Types { self: SymbolTable =>
// 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 typeListIsEmpty) {
- None // something is wrong: an array without a type arg.
- } else {
+ NoType // 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))))
+ if (args.tail forall (_ =:= args.head)) typeRef(pre, sym, List(args.head))
+ else if (args exists (arg => isPrimitiveValueClass(arg.typeSymbol))) ObjectTpe
+ else typeRef(pre, sym, List(lub(args)))
}
}
else transposeSafe(argss) match {
@@ -7107,30 +4387,28 @@ trait Types extends api.Types { self: SymbolTable =>
// 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
+ debuglog(s"transposed irregular matrix!? tps=$tps argss=$argss")
+ NoType
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
+ val args = map2(sym.typeParams, argsst) { (tparam, as0) =>
+ val as = as0.distinct
+ if (as.size == 1) as.head
+ else if (depth.isZero) {
+ log("Giving up merging args: can't unify %s under %s".format(as.mkString(", "), tparam.fullLocationString))
+ // Don't return "Any" (or "Nothing") when we have to give up due to
+ // recursion depth. Return NoType, which prevents us from poisoning
+ // lublist's results. It can recognize the recursion and deal with it, but
+ // only if we aren't returning invalid types.
+ NoType
}
else {
- if (tparam.variance == variance) lub(as, decr(depth))
- else if (tparam.variance == -variance) glb(as, decr(depth))
+ if (tparam.variance == variance) lub(as, depth.decr)
+ else if (tparam.variance == variance.flip) glb(as, depth.decr)
else {
- val l = lub(as, decr(depth))
- val g = glb(as, decr(depth))
+ val l = lub(as, depth.decr)
+ val g = glb(as, depth.decr)
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
+ 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
@@ -7141,22 +4419,22 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
}
- if (args contains NoType) None
- else Some(existentialAbstraction(capturedParams.toList, typeRef(pre, sym, args)))
+ if (args contains NoType) NoType
+ else existentialAbstraction(capturedParams.toList, typeRef(pre, sym, args))
}
} catch {
- case ex: MalformedType => None
+ case ex: MalformedType => NoType
}
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
- }
+ val pre = if (variance.isPositive) lub(pres, depth) else glb(pres, depth)
+ try singleType(pre, sym)
+ catch { case ex: MalformedType => NoType }
case ExistentialType(tparams, quantified) :: rest =>
- mergePrefixAndArgs(quantified :: rest, variance, depth) map (existentialAbstraction(tparams, _))
+ mergePrefixAndArgs(quantified :: rest, variance, depth) match {
+ case NoType => NoType
+ case tpe => existentialAbstraction(tparams, tpe)
+ }
case _ =>
abort(s"mergePrefixAndArgs($tps, $variance, $depth): unsupported tps")
}
@@ -7166,14 +4444,14 @@ trait Types extends api.Types { self: SymbolTable =>
/** 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, depth: Int) {
+ def addMember(thistp: Type, tp: Type, sym: Symbol, depth: Depth) {
assert(sym != NoSymbol)
// debuglog("add member " + sym+":"+sym.info+" to "+thistp) //DEBUG
if (!specializesSym(thistp, sym, depth)) {
if (sym.isTerm)
for (alt <- tp.nonPrivateDecl(sym.name).alternatives)
if (specializesSym(thistp, sym, thistp, alt, depth))
- tp.decls unlink alt;
+ tp.decls unlink alt
tp.decls enter sym
}
}
@@ -7186,51 +4464,6 @@ trait Types extends api.Types { self: SymbolTable =>
def inheritsJavaVarArgsMethod(clazz: Symbol) =
clazz.thisType.baseClasses exists isJavaVarargsAncestor
- /** 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 mt @ MethodType(params1, res) if isSameTypes(mt.paramTypes, pts) =>
- res
- case NullaryMethodType(res) if pts.isEmpty =>
- res
- case _ =>
- throw new NoCommonType(tps)
- }
-
// Errors and Diagnostics -----------------------------------------------------
/** A throwable signalling a type error */
@@ -7243,7 +4476,7 @@ trait Types extends api.Types { self: SymbolTable =>
/** 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()
+ if (settings.debug) printStackTrace()
}
class NoCommonType(tps: List[Type]) extends Throwable(
@@ -7255,26 +4488,28 @@ trait Types extends api.Types { self: SymbolTable =>
}
/** The current indentation string for traces */
- private var indent: String = ""
+ private var _indent: String = ""
+ protected def indent = _indent
+ protected def indent_=(value: String) = _indent = value
/** Perform operation `p` on arguments `tp1`, `arg2` and print trace of computation. */
protected def explain[T](op: String, p: (Type, T) => Boolean, tp1: Type, arg2: T): Boolean = {
- Console.println(indent + tp1 + " " + op + " " + arg2 + "?" /* + "("+tp1.getClass+","+arg2.getClass+")"*/)
+ inform(indent + tp1 + " " + op + " " + arg2 + "?" /* + "("+tp1.getClass+","+arg2.getClass+")"*/)
indent = indent + " "
val result = p(tp1, arg2)
indent = indent stripSuffix " "
- Console.println(indent + result)
+ inform(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 (settings.explaintypes) 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))
+ if (settings.explaintypes) withTypesExplained(op(found, required))
}
/** Execute `op` while printing a trace of the operations on types executed. */
@@ -7284,18 +4519,18 @@ trait Types extends api.Types { self: SymbolTable =>
}
def isUnboundedGeneric(tp: Type) = tp match {
- case t @ TypeRef(_, sym, _) => sym.isAbstractType && !(t <:< AnyRefClass.tpe)
+ case t @ TypeRef(_, sym, _) => sym.isAbstractType && !(t <:< AnyRefTpe)
case _ => false
}
def isBoundedGeneric(tp: Type) = tp match {
- case TypeRef(_, sym, _) if sym.isAbstractType => (tp <:< AnyRefClass.tpe)
+ case TypeRef(_, sym, _) if sym.isAbstractType => (tp <:< AnyRefTpe)
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 typeIsSubTypeOfSerializable) ps.toList
- else (ps :+ SerializableClass.tpe).toList
+ else (ps :+ SerializableTpe).toList
)
/** Adds the @uncheckedBound annotation if the given `tp` has type arguments */
@@ -7307,11 +4542,14 @@ trait Types extends api.Types { self: SymbolTable =>
/** Members of the given class, other than those inherited
* from Any or AnyRef.
*/
- def nonTrivialMembers(clazz: Symbol): Iterable[Symbol] =
- clazz.info.members filterNot (sym => sym.owner == ObjectClass || sym.owner == AnyClass)
+ def nonTrivialMembers(clazz: Symbol): Scope = clazz.info.members filterNot isUniversalMember
+
+ /** Members which can be imported into other scopes.
+ */
+ def importableMembers(pre: Type): Scope = pre.members filter isImportable
def objToAny(tp: Type): Type =
- if (!phase.erasedTypes && tp.typeSymbol == ObjectClass) AnyClass.tpe
+ if (!phase.erasedTypes && tp.typeSymbol == ObjectClass) AnyTpe
else tp
val shorthands = Set(
@@ -7324,46 +4562,57 @@ trait Types extends api.Types { self: SymbolTable =>
"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) {
- debugwarn("Exceeded recursion depth attempting to print type.")
- if (settings.debug.value)
- (new Throwable).printStackTrace
-
- "..."
- }
- else
- try {
- tostringRecursions += 1
- tpe.safeToString
- } finally {
- tostringRecursions -= 1
- }
-
// ----- Hoisted closures and convenience methods, for compile time reductions -------
- private[scala] val typeIsNotNull = (tp: Type) => tp.isNotNull
private[scala] val isTypeVar = (tp: Type) => tp.isInstanceOf[TypeVar]
private[scala] val typeContainsTypeVar = (tp: Type) => tp exists isTypeVar
private[scala] val typeIsNonClassType = (tp: Type) => tp.typeSymbolDirect.isNonClassType
private[scala] val typeIsExistentiallyBound = (tp: Type) => tp.typeSymbol.isExistentiallyBound
private[scala] val typeIsErroneous = (tp: Type) => tp.isErroneous
- private[scala] val typeIsError = (tp: Type) => tp.isError
- private[scala] val typeHasAnnotations = (tp: Type) => tp.annotations.nonEmpty
+ private[scala] val symTypeIsError = (sym: Symbol) => sym.tpe.isError
+ private[scala] val treeTpe = (t: Tree) => t.tpe
+ private[scala] val symTpe = (sym: Symbol) => sym.tpe
+ private[scala] val symInfo = (sym: Symbol) => sym.info
+ private[scala] val typeHasAnnotations = (tp: Type) => tp.annotations ne Nil
private[scala] val boundsContainType = (bounds: TypeBounds, tp: Type) => bounds containsType tp
private[scala] val typeListIsEmpty = (ts: List[Type]) => ts.isEmpty
- private[scala] val typeIsSubTypeOfSerializable = (tp: Type) => tp <:< SerializableClass.tpe
+ private[scala] val typeIsSubTypeOfSerializable = (tp: Type) => tp <:< SerializableTpe
private[scala] val typeIsNothing = (tp: Type) => tp.typeSymbolDirect eq NothingClass
private[scala] val typeIsAny = (tp: Type) => tp.typeSymbolDirect eq AnyClass
private[scala] val typeIsHigherKinded = (tp: Type) => tp.isHigherKinded
+ /** The maximum depth of type `tp` */
+ def typeDepth(tp: Type): Depth = tp match {
+ case TypeRef(pre, sym, args) => typeDepth(pre) max typeDepth(args).incr
+ case RefinedType(parents, decls) => typeDepth(parents) max symTypeDepth(decls.toList).incr
+ case TypeBounds(lo, hi) => typeDepth(lo) max typeDepth(hi)
+ case MethodType(paramtypes, result) => typeDepth(result)
+ case NullaryMethodType(result) => typeDepth(result)
+ case PolyType(tparams, result) => typeDepth(result) max symTypeDepth(tparams).incr
+ case ExistentialType(tparams, result) => typeDepth(result) max symTypeDepth(tparams).incr
+ case _ => Depth(1)
+ }
+
+ //OPT replaced with tailrecursive function to save on #closures
+ // was:
+ // var d = 0
+ // for (tp <- tps) d = d max by(tp) //!!!OPT!!!
+ // d
+ private[scala] def maxDepth(tps: List[Type]): Depth = {
+ @tailrec def loop(tps: List[Type], acc: Depth): Depth = tps match {
+ case tp :: rest => loop(rest, acc max typeDepth(tp))
+ case _ => acc
+ }
+ loop(tps, Depth.Zero)
+ }
+ private[scala] def maxbaseTypeSeqDepth(tps: List[Type]): Depth = {
+ @tailrec def loop(tps: List[Type], acc: Depth): Depth = tps match {
+ case tp :: rest => loop(rest, acc max tp.baseTypeSeqDepth)
+ case _ => acc
+ }
+ loop(tps, Depth.Zero)
+ }
+
@tailrec private def typesContain(tps: List[Type], sym: Symbol): Boolean = tps match {
case tp :: rest => (tp contains sym) || typesContain(rest, sym)
case _ => false
@@ -7400,10 +4649,15 @@ trait Types extends api.Types { self: SymbolTable =>
}
+object TypeConstants {
+ final val DefaultLogThreshhold = 50
+ final val LogPendingBaseTypesThreshold = DefaultLogThreshhold
+ final val LogVolatileThreshold = DefaultLogThreshhold
+}
+
object TypesStats {
import BaseTypeSeqsStats._
val rawTypeCount = Statistics.newCounter ("#raw type creations")
- val asSeenFromCount = Statistics.newCounter ("#asSeenFrom ops")
val subtypeCount = Statistics.newCounter ("#subtype ops")
val sametypeCount = Statistics.newCounter ("#sametype ops")
val lubCount = Statistics.newCounter ("#toplevel lubs/glbs")
@@ -7425,7 +4679,7 @@ object TypesStats {
val singletonBaseTypeSeqCount = Statistics.newSubCounter(" of which for singletons", baseTypeSeqCount)
val typeOpsStack = Statistics.newTimerStack()
- /** Commented out, because right now this does not inline, so creates a closure which will distort statistics
+ /* Commented out, because right now this does not inline, so creates a closure which will distort statistics
@inline final def timedTypeOp[T](c: Statistics.StackableTimer)(op: => T): T = {
val start = Statistics.pushTimer(typeOpsStack, c)
try op
diff --git a/src/reflect/scala/reflect/internal/Variance.scala b/src/reflect/scala/reflect/internal/Variance.scala
new file mode 100644
index 0000000000..ecc5d99a40
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Variance.scala
@@ -0,0 +1,90 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala
+package reflect
+package internal
+
+import Variance._
+
+/** Variances form a lattice:
+ *
+ * - Covariant -
+ * / \
+ * Invariant Bivariant
+ * \ /
+ * Contravariant
+ *
+ * The variance of a symbol within a type is calculated based on variance
+ * annotations, e.g. +A or -A, and the positions of the types in which the
+ * symbol appears. The actual mechanics are beyond the scope of this
+ * comment, but the essential operations on a Variance are:
+ *
+ * '&' - like bitwise AND. Unless all inputs have compatible variance,
+ * folding them across & will be invariant.
+ * '*' - like multiplication across { -1, 0, 1 } with contravariance as -1.
+ * flip - if contravariant or covariant, flip to the other; otherwise leave unchanged.
+ * cut - if bivariant, remain bivariant; otherwise become invariant.
+ *
+ * There is an important distinction between "isPositive" and "isCovariant".
+ * The former is true for both Covariant and Bivariant, but the latter is true
+ * only for Covariant.
+ */
+final class Variance private (val flags: Int) extends AnyVal {
+ def isBivariant = flags == 2
+ def isCovariant = flags == 1 // excludes bivariant
+ def isInvariant = flags == 0
+ def isContravariant = flags == -1 // excludes bivariant
+ def isPositive = flags > 0 // covariant or bivariant
+
+ def &(other: Variance): Variance = (
+ if (this == other) this
+ else if (this.isBivariant) other
+ else if (other.isBivariant) this
+ else Invariant
+ )
+
+ def *(other: Variance): Variance = (
+ if (other.isPositive) this
+ else if (other.isContravariant) this.flip
+ else this.cut
+ )
+
+ /** Flip between covariant and contravariant. I chose not to use unary_- because it doesn't stand out enough. */
+ def flip = if (isCovariant) Contravariant else if (isContravariant) Covariant else this
+
+ /** Map everything below bivariant to invariant. */
+ def cut = if (isBivariant) this else Invariant
+
+ /** The symbolic annotation used to indicate the given kind of variance. */
+ def symbolicString = (
+ if (isCovariant) "+"
+ else if (isContravariant) "-"
+ else ""
+ )
+
+ override def toString = (
+ if (isContravariant) "contravariant"
+ else if (isCovariant) "covariant"
+ else if (isInvariant) "invariant"
+ else "" // noisy to print bivariant on everything without type parameters
+ )
+}
+
+object Variance {
+ implicit class SbtCompat(val v: Variance) {
+ def < (other: Int) = v.flags < other
+ def > (other: Int) = v.flags > other
+ }
+
+ def fold(variances: List[Variance]): Variance = (
+ if (variances.isEmpty) Bivariant
+ else variances reduceLeft (_ & _)
+ )
+ val Bivariant = new Variance(2)
+ val Covariant = new Variance(1)
+ val Contravariant = new Variance(-1)
+ val Invariant = new Variance(0)
+}
diff --git a/src/reflect/scala/reflect/internal/Variances.scala b/src/reflect/scala/reflect/internal/Variances.scala
new file mode 100644
index 0000000000..cfe2ad8b87
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Variances.scala
@@ -0,0 +1,218 @@
+/* NSC -- new scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala
+package reflect
+package internal
+
+import Variance._
+import scala.collection.{ mutable, immutable }
+import scala.annotation.tailrec
+
+/** See comments at scala.reflect.internal.Variance.
+ */
+trait Variances {
+ self: SymbolTable =>
+
+ /** Used in Refchecks.
+ * TODO - eliminate duplication with varianceInType
+ */
+ class VarianceValidator extends Traverser {
+ private val escapedLocals = mutable.HashSet[Symbol]()
+ // A flag for when we're in a refinement, meaning method parameter types
+ // need to be checked.
+ private var inRefinement = false
+ @inline private def withinRefinement(body: => Type): Type = {
+ val saved = inRefinement
+ inRefinement = true
+ try body finally inRefinement = saved
+ }
+
+ /** Is every symbol in the owner chain between `site` and the owner of `sym`
+ * either a term symbol or private[this]? If not, add `sym` to the set of
+ * esacped locals.
+ * @pre sym.isLocalToThis
+ */
+ @tailrec final def checkForEscape(sym: Symbol, site: Symbol) {
+ if (site == sym.owner || site == sym.owner.moduleClass || site.hasPackageFlag) () // done
+ else if (site.isTerm || site.isPrivateLocal) checkForEscape(sym, site.owner) // ok - recurse to owner
+ else escapedLocals += sym
+ }
+
+ protected def issueVarianceError(base: Symbol, sym: Symbol, required: Variance): Unit = ()
+
+ // Flip occurrences of type parameters and parameters, unless
+ // - it's a constructor, or case class factory or extractor
+ // - it's a type parameter of tvar's owner.
+ def shouldFlip(sym: Symbol, tvar: Symbol) = (
+ sym.isParameter
+ && !(tvar.isTypeParameterOrSkolem && sym.isTypeParameterOrSkolem && tvar.owner == sym.owner)
+ )
+ // return Bivariant if `sym` is local to a term
+ // or is private[this] or protected[this]
+ def isLocalOnly(sym: Symbol) = !sym.owner.isClass || (
+ sym.isTerm // ?? shouldn't this be sym.owner.isTerm according to the comments above?
+ && (sym.isLocalToThis || sym.isSuperAccessor) // super accessors are implicitly local #4345
+ && !escapedLocals(sym)
+ )
+
+ private object ValidateVarianceMap extends TypeMap(trackVariance = true) {
+ private var base: Symbol = _
+
+ /** The variance of a symbol occurrence of `tvar` seen at the level of the definition of `base`.
+ * The search proceeds from `base` to the owner of `tvar`.
+ * Initially the state is covariant, but it might change along the search.
+ *
+ * A local alias type is treated as Bivariant;
+ * this is OK because we always expand aliases for variance checking.
+ * However, for an alias which might be externally visible, we must assume Invariant,
+ * because there may be references to the type parameter that are not checked,
+ * leading to unsoundness (see SI-6566).
+ */
+ def relativeVariance(tvar: Symbol): Variance = {
+ def nextVariance(sym: Symbol, v: Variance): Variance = (
+ if (shouldFlip(sym, tvar)) v.flip
+ else if (isLocalOnly(sym)) Bivariant
+ else if (sym.isAliasType) (
+ // Unsound pre-2.11 behavior preserved under -Xsource:2.10
+ if (settings.isScala211 || sym.isOverridingSymbol) Invariant
+ else {
+ deprecationWarning(sym.pos, s"Construct depends on unsound variance analysis and will not compile in scala 2.11 and beyond")
+ Bivariant
+ }
+ )
+ else v
+ )
+ def loop(sym: Symbol, v: Variance): Variance = (
+ if (sym == tvar.owner || v.isBivariant) v
+ else loop(sym.owner, nextVariance(sym, v))
+ )
+ loop(base, Covariant)
+ }
+ def isUncheckedVariance(tp: Type) = tp match {
+ case AnnotatedType(annots, _) => annots exists (_ matches definitions.uncheckedVarianceClass)
+ case _ => false
+ }
+
+ private def checkVarianceOfSymbol(sym: Symbol) {
+ val relative = relativeVariance(sym)
+ val required = relative * variance
+ if (!relative.isBivariant) {
+ def sym_s = s"$sym (${sym.variance}${sym.locationString})"
+ def base_s = s"$base in ${base.owner}" + (if (base.owner.isClass) "" else " in " + base.owner.enclClass)
+ log(s"verifying $sym_s is $required at $base_s")
+ if (sym.variance != required)
+ issueVarianceError(base, sym, required)
+ }
+ }
+ override def mapOver(decls: Scope): Scope = {
+ decls foreach (sym => withVariance(if (sym.isAliasType) Invariant else variance)(this(sym.info)))
+ decls
+ }
+ private def resultTypeOnly(tp: Type) = tp match {
+ case mt: MethodType => !inRefinement
+ case pt: PolyType => true
+ case _ => false
+ }
+
+ /** For PolyTypes, type parameters are skipped because they are defined
+ * explicitly (their TypeDefs will be passed here.) For MethodTypes, the
+ * same is true of the parameters (ValDefs) unless we are inside a
+ * refinement, in which case they are checked from here.
+ */
+ def apply(tp: Type): Type = tp match {
+ case _ if isUncheckedVariance(tp) => tp
+ case _ if resultTypeOnly(tp) => this(tp.resultType)
+ case TypeRef(_, sym, _) if sym.isAliasType => this(tp.normalize)
+ case TypeRef(_, sym, _) if !sym.variance.isInvariant => checkVarianceOfSymbol(sym) ; mapOver(tp)
+ case RefinedType(_, _) => withinRefinement(mapOver(tp))
+ case ClassInfoType(parents, _, _) => parents foreach this ; tp
+ case mt @ MethodType(_, result) => flipped(mt.paramTypes foreach this) ; this(result)
+ case _ => mapOver(tp)
+ }
+ def validateDefinition(base: Symbol) {
+ val saved = this.base
+ this.base = base
+ try apply(base.info)
+ finally this.base = saved
+ }
+ }
+
+ /** Validate variance of info of symbol `base` */
+ private def validateVariance(base: Symbol) {
+ ValidateVarianceMap validateDefinition base
+ }
+
+ override def traverse(tree: Tree) {
+ def sym = tree.symbol
+ // No variance check for object-private/protected methods/values.
+ // Or constructors, or case class factory or extractor.
+ def skip = (
+ sym == NoSymbol
+ || sym.isLocalToThis
+ || sym.owner.isConstructor
+ || sym.owner.isCaseApplyOrUnapply
+ )
+ tree match {
+ case defn: MemberDef if skip =>
+ debuglog(s"Skipping variance check of ${sym.defString}")
+ case ClassDef(_, _, _, _) | TypeDef(_, _, _, _) =>
+ validateVariance(sym)
+ super.traverse(tree)
+ // ModuleDefs need not be considered because they have been eliminated already
+ case ValDef(_, _, _, _) =>
+ validateVariance(sym)
+ case DefDef(_, _, tparams, vparamss, _, _) =>
+ validateVariance(sym)
+ traverseTrees(tparams)
+ traverseTreess(vparamss)
+ case Template(_, _, _) =>
+ super.traverse(tree)
+ case CompoundTypeTree(templ) =>
+ super.traverse(tree)
+
+ // SI-7872 These two cases make sure we don't miss variance exploits
+ // in originals, e.g. in `foo[({type l[+a] = List[a]})#l]`
+ case tt @ TypeTree() if tt.original != null =>
+ super.traverse(tt.original)
+ case tt : TypTree =>
+ super.traverse(tt)
+
+ case _ =>
+ }
+ }
+ }
+
+ /** Compute variance of type parameter `tparam` in all types `tps`. */
+ def varianceInTypes(tps: List[Type])(tparam: Symbol): Variance =
+ fold(tps map (tp => varianceInType(tp)(tparam)))
+
+ /** Compute variance of type parameter `tparam` in type `tp`. */
+ def varianceInType(tp: Type)(tparam: Symbol): Variance = {
+ def inArgs(sym: Symbol, args: List[Type]): Variance = fold(map2(args, sym.typeParams)((a, p) => inType(a) * p.variance))
+ def inSyms(syms: List[Symbol]): Variance = fold(syms map inSym)
+ def inTypes(tps: List[Type]): Variance = fold(tps map inType)
+
+ def inSym(sym: Symbol): Variance = if (sym.isAliasType) inType(sym.info).cut else inType(sym.info)
+ def inType(tp: Type): Variance = tp match {
+ case ErrorType | WildcardType | NoType | NoPrefix => Bivariant
+ case ThisType(_) | ConstantType(_) => Bivariant
+ case TypeRef(_, `tparam`, _) => Covariant
+ case BoundedWildcardType(bounds) => inType(bounds)
+ case NullaryMethodType(restpe) => inType(restpe)
+ case SingleType(pre, sym) => inType(pre)
+ case TypeRef(pre, _, _) if tp.isHigherKinded => inType(pre) // a type constructor cannot occur in tp's args
+ case TypeRef(pre, sym, args) => inType(pre) & inArgs(sym, args)
+ case TypeBounds(lo, hi) => inType(lo).flip & inType(hi)
+ case RefinedType(parents, defs) => inTypes(parents) & inSyms(defs.toList)
+ case MethodType(params, restpe) => inSyms(params).flip & inType(restpe)
+ case PolyType(tparams, restpe) => inSyms(tparams).flip & inType(restpe)
+ case ExistentialType(tparams, restpe) => inSyms(tparams) & inType(restpe)
+ case AnnotatedType(annots, tp) => inTypes(annots map (_.atp)) & inType(tp)
+ }
+
+ inType(tp)
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/annotations/compileTimeOnly.scala b/src/reflect/scala/reflect/internal/annotations/compileTimeOnly.scala
deleted file mode 100644
index 058ff61fbf..0000000000
--- a/src/reflect/scala/reflect/internal/annotations/compileTimeOnly.scala
+++ /dev/null
@@ -1,31 +0,0 @@
-package scala.reflect
-package internal
-package annotations
-
-import scala.annotation.meta._
-
-/**
- * An annotation that designates a member should not be referred to after
- * type checking (which includes macro expansion); it must only be used in
- * the arguments of some other macro that will eliminate it from the AST.
- *
- * Later on, this annotation should be removed and implemented with domain-specific macros.
- * If a certain method `inner` mustn't be called outside the context of a given macro `outer`,
- * then it should itself be declared as a macro.
- *
- * Approach #1. Expansion of `inner` checks whether its enclosures contain `outer` and
- * report an error if `outer` is not detected. In principle, we could use this approach right now,
- * but currently enclosures are broken, because contexts aren't exactly famous for keeping precise
- * track of the stack of the trees being typechecked.
- *
- * Approach #2. Default implementation of `inner` is just an invocation of `c.abort`.
- * `outer` is an untyped macro, which expands into a block, which contains a redefinition of `inner`
- * and a call to itself. The redefined `inner` could either be a stub like `Expr.splice` or carry out
- * domain-specific logic.
- *
- * @param message the error message to print during compilation if a reference remains
- * after type checking
- * @since 2.10.1
- */
-@getter @setter @beanGetter @beanSetter
-final class compileTimeOnly(message: String) extends scala.annotation.StaticAnnotation
diff --git a/src/reflect/scala/reflect/internal/annotations/package.scala b/src/reflect/scala/reflect/internal/annotations/package.scala
new file mode 100644
index 0000000000..ef299a600c
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/annotations/package.scala
@@ -0,0 +1,6 @@
+package scala.reflect.internal
+
+package object annotations {
+ @deprecated("Use scala.annotation.compileTimeOnly instead", "2.11.0")
+ type compileTimeOnly = scala.annotation.compileTimeOnly
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/internal/pickling/ByteCodecs.scala b/src/reflect/scala/reflect/internal/pickling/ByteCodecs.scala
index 367a3b8b19..8615e34fad 100644
--- a/src/reflect/scala/reflect/internal/pickling/ByteCodecs.scala
+++ b/src/reflect/scala/reflect/internal/pickling/ByteCodecs.scala
@@ -5,7 +5,8 @@
** /____/\___/_/ |_/____/_/ | | **
** |/ **
\* */
-package scala.reflect.internal.pickling
+package scala
+package reflect.internal.pickling
object ByteCodecs {
@@ -127,7 +128,7 @@ object ByteCodecs {
var j = 0
val dstlen = (srclen * 7 + 7) / 8
while (i + 7 < srclen) {
- var out: Int = src(i)
+ var out: Int = src(i).toInt
var in: Byte = src(i + 1)
src(j) = (out | (in & 0x01) << 7).toByte
out = in >>> 1
@@ -152,7 +153,7 @@ object ByteCodecs {
j += 7
}
if (i < srclen) {
- var out: Int = src(i)
+ var out: Int = src(i).toInt
if (i + 1 < srclen) {
var in: Byte = src(i + 1)
src(j) = (out | (in & 0x01) << 7).toByte; j += 1
@@ -195,10 +196,10 @@ object ByteCodecs {
*
* Sometimes returns (length+1) of the decoded array. Example:
*
- * scala> val enc = reflect.generic.ByteCodecs.encode(Array(1,2,3))
+ * scala> val enc = scala.reflect.generic.ByteCodecs.encode(Array(1,2,3))
* enc: Array[Byte] = Array(2, 5, 13, 1)
*
- * scala> reflect.generic.ByteCodecs.decode(enc)
+ * scala> scala.reflect.generic.ByteCodecs.decode(enc)
* res43: Int = 4
*
* scala> enc
@@ -211,11 +212,3 @@ object ByteCodecs {
decode7to8(xs, len)
}
}
-
-
-
-
-
-
-
-
diff --git a/src/reflect/scala/reflect/internal/pickling/PickleBuffer.scala b/src/reflect/scala/reflect/internal/pickling/PickleBuffer.scala
index 6170fcbb90..a814256f8e 100644
--- a/src/reflect/scala/reflect/internal/pickling/PickleBuffer.scala
+++ b/src/reflect/scala/reflect/internal/pickling/PickleBuffer.scala
@@ -3,7 +3,8 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
package pickling
@@ -62,11 +63,8 @@ class PickleBuffer(data: Array[Byte], from: Int, to: Int) {
writeByte((x & 0x7f).toInt)
}
- /** Write a natural number <code>x</code> at position <code>pos</code>.
+ /** Write a natural number `x` at position `pos`.
* 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) {
@@ -81,7 +79,7 @@ class PickleBuffer(data: Array[Byte], from: Int, to: Int) {
if (y != 0) patchNatPrefix(y)
}
- /** Write a long number <code>x</code> in signed big endian format, base 256.
+ /** Write a long number `x` in signed big endian format, base 256.
*
* @param x The long number to be written.
*/
@@ -94,12 +92,9 @@ class PickleBuffer(data: Array[Byte], from: Int, to: Int) {
// -- 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
+ val x = bytes(readIndex).toInt; readIndex += 1; x
}
/** Read a natural number in big endian format, base 128.
@@ -110,9 +105,9 @@ class PickleBuffer(data: Array[Byte], from: Int, to: Int) {
var b = 0L
var x = 0L
do {
- b = readByte()
+ b = readByte().toLong
x = (x << 7) + (b & 0x7f)
- } while ((b & 0x80) != 0L);
+ } while ((b & 0x80) != 0L)
x
}
@@ -151,18 +146,14 @@ class PickleBuffer(data: Array[Byte], from: Int, to: Int) {
result.toIndexedSeq
}
- /** Perform operation <code>op</code> until the condition
- * <code>readIndex == end</code> is satisfied.
+ /** Perform operation `op` until the condition
+ * `readIndex == end` 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);
+ if (readIndex == end) List() else op() :: until(end, op)
- /** Perform operation <code>op</code> the number of
+ /** Perform operation `op` the number of
* times specified. Concatenate the results into a list.
*/
def times[T](n: Int, op: ()=>T): List[T] =
diff --git a/src/reflect/scala/reflect/internal/pickling/PickleFormat.scala b/src/reflect/scala/reflect/internal/pickling/PickleFormat.scala
index 16747af08a..ce0ceec688 100644
--- a/src/reflect/scala/reflect/internal/pickling/PickleFormat.scala
+++ b/src/reflect/scala/reflect/internal/pickling/PickleFormat.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package internal
package pickling
@@ -56,7 +57,7 @@ object PickleFormat {
* | 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
+ * | 47 DEBRUIJNINDEXtpe len_Nat level_Nat index_Nat /* no longer needed */
* | 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}
@@ -115,7 +116,6 @@ object PickleFormat {
*/
val MajorVersion = 5
val MinorVersion = 0
- def VersionString = "V" + MajorVersion + "." + MinorVersion
final val TERMname = 1
final val TYPEname = 2
@@ -161,7 +161,7 @@ object PickleFormat {
final val ANNOTARGARRAY = 44
final val SUPERtpe = 46
- final val DEBRUIJNINDEXtpe = 47
+ final val DEBRUIJNINDEXtpe = 47 // no longer generated
final val EXISTENTIALtpe = 48
final val TREE = 49 // prefix code that means a tree is coming
diff --git a/src/reflect/scala/reflect/internal/pickling/Translations.scala b/src/reflect/scala/reflect/internal/pickling/Translations.scala
new file mode 100644
index 0000000000..d924cb3a0c
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/pickling/Translations.scala
@@ -0,0 +1,129 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala
+package reflect
+package internal
+package pickling
+
+import PickleFormat._
+import util.shortClassOfInstance
+
+trait Translations {
+ self: SymbolTable =>
+
+ def isTreeSymbolPickled(code: Int): Boolean = (code: @annotation.switch) match {
+ case PACKAGEtree | CLASStree | MODULEtree | VALDEFtree | DEFDEFtree | TYPEDEFtree | LABELtree => true
+ case IMPORTtree | TEMPLATEtree | BINDtree | FUNCTIONtree | RETURNtree => true
+ case APPLYDYNAMICtree | SUPERtree | THIStree | SELECTtree | IDENTtree => true
+ case _ => false
+ }
+ /** This method should be equivalent to tree.hasSymbolField, but that method
+ * doesn't do us any good when we're unpickling because we need to know based
+ * on the Int tag - the tree doesn't exist yet. Thus, this method is documentation only.
+ */
+ def isTreeSymbolPickled(tree: Tree): Boolean = isTreeSymbolPickled(picklerSubTag(tree))
+
+ // The ad hoc pattern matching of tuples out of AnyRefs is a
+ // truly terrible idea. It reaches the height of its powers in
+ // combination with scala's insistence on helpfully tupling
+ // multiple arguments passed to a single-arg AnyRef.
+ def picklerTag(ref: AnyRef): Int = ref match {
+ case tp: Type => picklerTag(tp)
+ case sym: Symbol => picklerTag(sym)
+ case const: Constant => LITERAL + const.tag
+ case _: Tree => TREE // its sub tag more precisely identifies it
+ case _: TermName => TERMname
+ case _: TypeName => TYPEname
+ case _: ArrayAnnotArg => ANNOTARGARRAY // an array of annotation arguments
+ case _: AnnotationInfo => ANNOTINFO // annotations on types (not linked to a symbol)
+ case (_: Symbol, _: AnnotationInfo) => SYMANNOT // symbol annotations, i.e. on terms
+ case (_: Symbol, _: List[_]) => CHILDREN // the direct subclasses of a sealed symbol
+ case _: Modifiers => MODIFIERS
+ case _ => sys.error(s"unpicklable entry ${shortClassOfInstance(ref)} $ref")
+ }
+
+ /** Local symbols only. The assessment of locality depends
+ * on convoluted conditions which depends in part on the root
+ * symbol being pickled, so it cannot be reproduced here.
+ * The pickler tags at stake are EXTMODCLASSref and EXTref.
+ * Those tags are never produced here - such symbols must be
+ * excluded prior to calling this method.
+ */
+ def picklerTag(sym: Symbol): Int = sym match {
+ case NoSymbol => NONEsym
+ case _: ClassSymbol => CLASSsym
+ case _: TypeSymbol if sym.isAbstractType => TYPEsym
+ case _: TypeSymbol => ALIASsym
+ case _: TermSymbol if sym.isModule => MODULEsym
+ case _: TermSymbol => VALsym
+ }
+
+ def picklerTag(tpe: Type): Int = tpe match {
+ case NoType => NOtpe
+ case NoPrefix => NOPREFIXtpe
+ case _: ThisType => THIStpe
+ case _: SingleType => SINGLEtpe
+ case _: SuperType => SUPERtpe
+ case _: ConstantType => CONSTANTtpe
+ case _: TypeBounds => TYPEBOUNDStpe
+ case _: TypeRef => TYPEREFtpe
+ case _: RefinedType => REFINEDtpe
+ case _: ClassInfoType => CLASSINFOtpe
+ case _: MethodType => METHODtpe
+ case _: PolyType => POLYtpe
+ case _: NullaryMethodType => POLYtpe // bad juju, distinct ints are not at a premium!
+ case _: ExistentialType => EXISTENTIALtpe
+ case StaticallyAnnotatedType(_, _) => ANNOTATEDtpe
+ case _: AnnotatedType => picklerTag(tpe.underlying)
+ }
+
+ def picklerSubTag(tree: Tree): Int = tree match {
+ case EmptyTree => EMPTYtree
+ case _: PackageDef => PACKAGEtree
+ case _: ClassDef => CLASStree
+ case _: ModuleDef => MODULEtree
+ case _: ValDef => VALDEFtree
+ case _: DefDef => DEFDEFtree
+ case _: TypeDef => TYPEDEFtree
+ case _: LabelDef => LABELtree
+ case _: Import => IMPORTtree
+ // case _: DocDef => DOCDEFtree
+ case _: Template => TEMPLATEtree
+ case _: Block => BLOCKtree
+ case _: CaseDef => CASEtree
+ case _: Alternative => ALTERNATIVEtree
+ case _: Star => STARtree
+ case _: Bind => BINDtree
+ case _: UnApply => UNAPPLYtree
+ case _: ArrayValue => ARRAYVALUEtree
+ case _: Function => FUNCTIONtree
+ case _: Assign => ASSIGNtree
+ case _: If => IFtree
+ case _: Match => MATCHtree
+ case _: Return => RETURNtree
+ case _: Try => TREtree // TREtree?
+ case _: Throw => THROWtree
+ case _: New => NEWtree
+ case _: Typed => TYPEDtree
+ case _: TypeApply => TYPEAPPLYtree
+ case _: Apply => APPLYtree
+ case _: ApplyDynamic => APPLYDYNAMICtree
+ case _: Super => SUPERtree
+ case _: This => THIStree
+ case _: Select => SELECTtree
+ case _: Ident => IDENTtree
+ case _: Literal => LITERALtree
+ case _: TypeTree => TYPEtree
+ case _: Annotated => ANNOTATEDtree
+ case _: SingletonTypeTree => SINGLETONTYPEtree
+ case _: SelectFromTypeTree => SELECTFROMTYPEtree
+ case _: CompoundTypeTree => COMPOUNDTYPEtree
+ case _: AppliedTypeTree => APPLIEDTYPEtree
+ case _: TypeBoundsTree => TYPEBOUNDStree
+ case _: ExistentialTypeTree => EXISTENTIALTYPEtree
+ }
+}
+
diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
index 603fff4f1c..64a1a44722 100644
--- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
+++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
@@ -3,7 +3,8 @@
* @author Martin Odersky
*/
-package scala.reflect
+package scala
+package reflect
package internal
package pickling
@@ -21,15 +22,15 @@ import scala.annotation.switch
* @version 1.0
*/
abstract class UnPickler {
- val global: SymbolTable
- import global._
+ val symbolTable: SymbolTable
+ import symbolTable._
/** 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 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) {
@@ -64,36 +65,38 @@ abstract class UnPickler {
/** A map from symbols to their associated `decls` scopes */
private val symScopes = mutable.HashMap[Symbol, Scope]()
+ private def expect(expected: Int, msg: => String) {
+ val tag = readByte()
+ if (tag != expected)
+ errorBadSignature(s"$msg ($tag)")
+ }
+
//println("unpickled " + classRoot + ":" + classRoot.rawInfo + ", " + moduleRoot + ":" + moduleRoot.rawInfo);//debug
+ @inline private def runAtIndex[T](i: Int)(body: => T): T = {
+ val saved = readIndex
+ readIndex = index(i)
+ try body finally readIndex = saved
+ }
+
// Laboriously unrolled for performance.
def run() {
var i = 0
while (i < index.length) {
- if (entries(i) == null && isSymbolEntry(i)) {
- val savedIndex = readIndex
- readIndex = index(i)
- entries(i) = readSymbol()
- readIndex = savedIndex
- }
+ if (entries(i) == null && isSymbolEntry(i))
+ runAtIndex(i)(entries(i) = readSymbol())
+
i += 1
}
+
// read children last, fix for #3951
i = 0
while (i < index.length) {
if (entries(i) == null) {
- if (isSymbolAnnotationEntry(i)) {
- val savedIndex = readIndex
- readIndex = index(i)
- readSymbolAnnotation()
- readIndex = savedIndex
- }
- else if (isChildrenEntry(i)) {
- val savedIndex = readIndex
- readIndex = index(i)
- readChildren()
- readIndex = savedIndex
- }
+ if (isSymbolAnnotationEntry(i))
+ runAtIndex(i)(readSymbolAnnotation())
+ else if (isChildrenEntry(i))
+ runAtIndex(i)(readChildren())
}
i += 1
}
@@ -144,6 +147,11 @@ abstract class UnPickler {
tag == CHILDREN
}
+ private def maybeReadSymbol(): Either[Int, Symbol] = readNat() match {
+ case index if isSymbolRef(index) => Right(at(index, readSymbol))
+ case index => Left(index)
+ }
+
/** Does entry represent a refinement symbol?
* pre: Entry is a class symbol
*/
@@ -159,9 +167,9 @@ abstract class UnPickler {
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.
+ /** If entry at `i` is undefined, define it by performing
+ * operation `op` with `readIndex at start of i'th
+ * entry. Restore `readIndex` afterwards.
*/
protected def at[T <: AnyRef](i: Int, op: () => T): T = {
var r = entries(i)
@@ -186,13 +194,12 @@ abstract class UnPickler {
case _ => errorBadSignature("bad name tag: " + tag)
}
}
- protected def readTermName(): TermName = readName().toTermName
- protected def readTypeName(): TypeName = readName().toTypeName
+ private def readEnd() = readNat() + readIndex
/** Read a symbol */
protected def readSymbol(): Symbol = {
val tag = readByte()
- val end = readNat() + readIndex
+ val end = readEnd()
def atEnd = readIndex == end
def readExtSymbol(): Symbol = {
@@ -222,6 +229,20 @@ abstract class UnPickler {
NoSymbol
}
+ def moduleAdvice(missing: String): String = {
+ val module =
+ if (missing.startsWith("scala.xml")) Some(("org.scala-lang.modules", "scala-xml"))
+ else if (missing.startsWith("scala.util.parsing")) Some(("org.scala-lang.modules", "scala-parser-combinators"))
+ else if (missing.startsWith("scala.swing")) Some(("org.scala-lang.modules", "scala-swing"))
+ else if (missing.startsWith("scala.util.continuations")) Some(("org.scala-lang.plugins", "scala-continuations-library"))
+ else None
+
+ (module map { case (group, art) =>
+ s"""\n(NOTE: It looks like the $art module is missing; try adding a dependency on "$group" : "$art".
+ | See http://docs.scala-lang.org/overviews/core/scala-2.11.html for more information.)""".stripMargin
+ } getOrElse "")
+ }
+
// (1) Try name.
fromName(name) orElse {
// (2) Try with expanded name. Can happen if references to private
@@ -233,11 +254,12 @@ abstract class UnPickler {
// (4) Call the mirror's "missing" hook.
adjust(mirrorThatLoaded(owner).missingHook(owner, name)) orElse {
// (5) Create a stub symbol to defer hard failure a little longer.
+ val fullName = s"${owner.fullName}.$name"
val missingMessage =
- s"""|bad symbolic reference. A signature in $filename refers to ${name.longString}
- |in ${owner.kindString} ${owner.fullName} which is not available.
- |It may be completely missing from the current classpath, or the version on
- |the classpath might be incompatible with the version used when compiling $filename.""".stripMargin
+ s"""|bad symbolic reference to $fullName encountered in class file '$filename'.
+ |Cannot access ${name.longString} in ${owner.kindString} ${owner.fullName}. The current classpath may be
+ |missing a definition for $fullName, or $filename may have been compiled against a version that's
+ |incompatible with the one found on the current classpath.${moduleAdvice(fullName)}""".stripMargin
owner.newStubSymbol(name, missingMessage)
}
}
@@ -256,14 +278,11 @@ abstract class UnPickler {
val name = at(nameref, readName)
val owner = readSymbolRef()
val flags = pickledToRawFlags(readLongNat())
- var inforef = readNat()
- val privateWithin =
- if (!isSymbolRef(inforef)) NoSymbol
- else {
- val pw = at(inforef, readSymbol)
- inforef = readNat()
- pw
- }
+
+ val (privateWithin, inforef) = maybeReadSymbol() match {
+ case Left(index) => NoSymbol -> index
+ case Right(sym) => sym -> readNat()
+ }
def isModuleFlag = (flags & MODULE) != 0L
def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner)
@@ -271,6 +290,7 @@ abstract class UnPickler {
def pflags = flags & PickledFlags
def finishSym(sym: Symbol): Symbol = {
+ markFlagsCompleted(sym)(mask = AllFlags)
sym.privateWithin = privateWithin
sym.info = (
if (atEnd) {
@@ -305,7 +325,7 @@ abstract class UnPickler {
sym
case MODULEsym =>
- val clazz = at(inforef, () => readType()).typeSymbol // after the NMT_TRANSITION period, we can leave off the () => ... ()
+ val clazz = at(inforef, () => readType()).typeSymbol // after NMT_TRANSITION, we can leave off the () => ... ()
if (isModuleRoot) moduleRoot setFlag pflags
else owner.newLinkedModule(clazz, pflags)
case VALsym =>
@@ -317,84 +337,48 @@ abstract class UnPickler {
})
}
- /** Read a type
- *
- * @param forceProperType is used to ease the transition to NullaryMethodTypes (commentmarker: NMT_TRANSITION)
- * the flag say that a type of kind * is expected, so that PolyType(tps, restpe) can be disambiguated to PolyType(tps, NullaryMethodType(restpe))
- * (if restpe is not a ClassInfoType, a MethodType or a NullaryMethodType, which leaves TypeRef/SingletonType -- the latter would make the polytype a type constructor)
- */
protected def readType(forceProperType: Boolean = false): Type = {
val tag = readByte()
- val end = readNat() + readIndex
+ val end = readEnd()
+ @inline def all[T](body: => T): List[T] = until(end, () => body)
+
+ def readTypes() = all(readTypeRef)
+ def readSymbols() = all(readSymbolRef)
+ def readAnnots() = all(readAnnotationRef)
+
+ // if the method is overloaded, the params cannot be determined (see readSymbol) => return NoType.
+ // Only happen for trees, "case Apply" in readTree() takes care of selecting the correct
+ // alternative after parsing the arguments.
+ def MethodTypeRef(restpe: Type, params: List[Symbol]): Type = (
+ if (restpe == NoType || (params contains NoSymbol)) NoType
+ else MethodType(params, restpe)
+ )
+ def PolyOrNullaryType(restpe: Type, tparams: List[Symbol]): Type = tparams match {
+ case Nil => NullaryMethodType(restpe)
+ case _ => PolyType(tparams, restpe)
+ }
+ def CompoundType(clazz: Symbol, parents: List[Type]): Type = tag match {
+ case REFINEDtpe => RefinedType(parents, symScope(clazz), clazz)
+ case CLASSINFOtpe => ClassInfoType(parents, symScope(clazz), clazz)
+ }
+
+ // We're stuck with the order types are pickled in, but with judicious use
+ // of named parameters we can recapture a declarative flavor in a few cases.
+ // But it's still a rat's nest of adhockery.
(tag: @switch) match {
- case NOtpe =>
- NoType
- case NOPREFIXtpe =>
- NoPrefix
- case THIStpe =>
- ThisType(readSymbolRef())
- case SINGLEtpe =>
- SingleType(readTypeRef(), readSymbolRef()) // !!! was singleType
- case SUPERtpe =>
- val thistpe = readTypeRef()
- val supertpe = readTypeRef()
- SuperType(thistpe, supertpe)
- case CONSTANTtpe =>
- ConstantType(readConstantRef())
- case TYPEREFtpe =>
- val pre = readTypeRef()
- val sym = readSymbolRef()
- 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()
- newExistentialType(until(end, readSymbolRef), restpe)
-
- case ANNOTATEDtpe =>
- var typeRef = readNat()
- val selfsym = if (isSymbolRef(typeRef)) {
- val s = at(typeRef, readSymbol)
- typeRef = readNat()
- s
- } else NoSymbol // selfsym can go.
- val tp = at(typeRef, () => readType(forceProperType)) // NMT_TRANSITION
- val annots = until(end, readAnnotationRef)
- if (selfsym == NoSymbol) AnnotatedType(annots, tp, selfsym)
- else tp
- case _ =>
- noSuchTypeTag(tag, end)
+ case NOtpe => NoType
+ case NOPREFIXtpe => NoPrefix
+ case THIStpe => ThisType(readSymbolRef())
+ case SINGLEtpe => SingleType(readTypeRef(), readSymbolRef())
+ case SUPERtpe => SuperType(readTypeRef(), readTypeRef())
+ case CONSTANTtpe => ConstantType(readConstantRef())
+ case TYPEREFtpe => TypeRef(readTypeRef(), readSymbolRef(), readTypes())
+ case TYPEBOUNDStpe => TypeBounds(readTypeRef(), readTypeRef())
+ case REFINEDtpe | CLASSINFOtpe => CompoundType(readSymbolRef(), readTypes())
+ case METHODtpe => MethodTypeRef(readTypeRef(), readSymbols())
+ case POLYtpe => PolyOrNullaryType(readTypeRef(), readSymbols())
+ case EXISTENTIALtpe => ExistentialType(underlying = readTypeRef(), quantified = readSymbols())
+ case ANNOTATEDtpe => AnnotatedType(underlying = readTypeRef(), annotations = readAnnots())
}
}
@@ -431,7 +415,7 @@ abstract class UnPickler {
protected def readChildren() {
val tag = readByte()
assert(tag == CHILDREN)
- val end = readNat() + readIndex
+ val end = readEnd()
val target = readSymbolRef()
while (readIndex != end) target addChild readSymbolRef()
}
@@ -450,7 +434,7 @@ abstract class UnPickler {
*/
private def readArrayAnnot() = {
readByte() // skip the `annotargarray` tag
- val end = readNat() + readIndex
+ val end = readEnd()
until(end, () => readClassfileAnnotArg(readNat())).toArray(JavaArgumentTag)
}
protected def readClassfileAnnotArg(i: Int): ClassfileAnnotArg = bytes(index(i)) match {
@@ -483,10 +467,8 @@ abstract class UnPickler {
* the symbol it requests. Called at top-level, for all
* (symbol, annotInfo) entries. */
protected def readSymbolAnnotation() {
- val tag = readByte()
- if (tag != SYMANNOT)
- errorBadSignature("symbol annotation expected ("+ tag +")")
- val end = readNat() + readIndex
+ expect(SYMANNOT, "symbol annotation expected")
+ val end = readEnd()
val target = readSymbolRef()
target.addAnnotation(readAnnotationInfo(end))
}
@@ -497,264 +479,105 @@ abstract class UnPickler {
val tag = readByte()
if (tag != ANNOTINFO)
errorBadSignature("annotation expected (" + tag + ")")
- val end = readNat() + readIndex
+ val end = readEnd()
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()
+ private def readNonEmptyTree(tag: Int, end: Int): Tree = {
+ @inline def all[T](body: => T): List[T] = until(end, () => body)
+ @inline def rep[T](body: => T): List[T] = times(readNat(), () => body)
+
+ // !!! What is this doing here?
+ def fixApply(tree: Apply, tpe: Type): Apply = {
+ val Apply(fun, args) = tree
+ if (fun.symbol.isOverloaded) {
+ fun setType fun.symbol.info
+ inferMethodAlternative(fun, args map (_.tpe), tpe)
+ }
+ tree
}
- /** Read a Symbol and a Name */
- def setSymName() {
- symbol = readSymbolRef()
- name = readNameRef()
+ def ref() = readTreeRef()
+ def caseRef() = readCaseDefRef()
+ def modsRef() = readModifiersRef()
+ def implRef() = readTemplateRef()
+ def nameRef() = readNameRef()
+ def tparamRef() = readTypeDefRef()
+ def vparamRef() = readValDefRef()
+ def memberRef() = readMemberDefRef()
+ def constRef() = readConstantRef()
+ def idRef() = readIdentRef()
+ def termNameRef() = readNameRef().toTermName
+ def typeNameRef() = readNameRef().toTypeName
+ def refTreeRef() = ref() match {
+ case t: RefTree => t
+ case t => errorBadSignature("RefTree expected, found " + t.shortClass)
}
- /** Read a Symbol */
- def setSym() {
- symbol = readSymbolRef()
+ def selectorsRef() = all(ImportSelector(nameRef(), -1, nameRef(), -1))
+
+ /** A few of the most popular trees have been pulled to the top for
+ * switch efficiency purposes.
+ */
+ def readTree(tpe: Type): Tree = (tag: @switch) match {
+ case IDENTtree => Ident(nameRef)
+ case SELECTtree => Select(ref, nameRef)
+ case APPLYtree => fixApply(Apply(ref, all(ref)), tpe) // !!!
+ case BINDtree => Bind(nameRef, ref)
+ case BLOCKtree => all(ref) match { case stats :+ expr => Block(stats, expr) }
+ case IFtree => If(ref, ref, ref)
+ case LITERALtree => Literal(constRef)
+ case TYPEAPPLYtree => TypeApply(ref, all(ref))
+ case TYPEDtree => Typed(ref, ref)
+ case ALTERNATIVEtree => Alternative(all(ref))
+ case ANNOTATEDtree => Annotated(ref, ref)
+ case APPLIEDTYPEtree => AppliedTypeTree(ref, all(ref))
+ case APPLYDYNAMICtree => ApplyDynamic(ref, all(ref))
+ case ARRAYVALUEtree => ArrayValue(ref, all(ref))
+ case ASSIGNtree => Assign(ref, ref)
+ case CASEtree => CaseDef(ref, ref, ref)
+ case CLASStree => ClassDef(modsRef, typeNameRef, rep(tparamRef), implRef)
+ case COMPOUNDTYPEtree => CompoundTypeTree(implRef)
+ case DEFDEFtree => DefDef(modsRef, termNameRef, rep(tparamRef), rep(rep(vparamRef)), ref, ref)
+ case EXISTENTIALTYPEtree => ExistentialTypeTree(ref, all(memberRef))
+ case FUNCTIONtree => Function(rep(vparamRef), ref)
+ case IMPORTtree => Import(ref, selectorsRef)
+ case LABELtree => LabelDef(termNameRef, rep(idRef), ref)
+ case MATCHtree => Match(ref, all(caseRef))
+ case MODULEtree => ModuleDef(modsRef, termNameRef, implRef)
+ case NEWtree => New(ref)
+ case PACKAGEtree => PackageDef(refTreeRef, all(ref))
+ case RETURNtree => Return(ref)
+ case SELECTFROMTYPEtree => SelectFromTypeTree(ref, typeNameRef)
+ case SINGLETONTYPEtree => SingletonTypeTree(ref)
+ case STARtree => Star(ref)
+ case SUPERtree => Super(ref, typeNameRef)
+ case TEMPLATEtree => Template(rep(ref), vparamRef, all(ref))
+ case THIStree => This(typeNameRef)
+ case THROWtree => Throw(ref)
+ case TREtree => Try(ref, rep(caseRef), ref)
+ case TYPEBOUNDStree => TypeBoundsTree(ref, ref)
+ case TYPEDEFtree => TypeDef(modsRef, typeNameRef, rep(tparamRef), ref)
+ case TYPEtree => TypeTree()
+ case UNAPPLYtree => UnApply(ref, all(ref))
+ case VALDEFtree => ValDef(modsRef, termNameRef, ref, ref)
+ case _ => noSuchTreeTag(tag, end)
}
- val t = tag match {
- case EMPTYtree =>
- EmptyTree
-
- case PACKAGEtree =>
- setSym()
- val pid = readTreeRef().asInstanceOf[RefTree]
- val stats = until(end, readTreeRef)
- PackageDef(pid, stats)
-
- case CLASStree =>
- setSymModsName()
- val impl = readTemplateRef()
- val tparams = until(end, readTypeDefRef)
- ClassDef(mods, name.toTypeName, tparams, impl)
-
- case MODULEtree =>
- setSymModsName()
- ModuleDef(mods, name.toTermName, readTemplateRef())
-
- case VALDEFtree =>
- setSymModsName()
- val tpt = readTreeRef()
- val rhs = readTreeRef()
- ValDef(mods, name.toTermName, tpt, rhs)
-
- case DEFDEFtree =>
- setSymModsName()
- val tparams = times(readNat(), readTypeDefRef)
- val vparamss = times(readNat(), () => times(readNat(), readValDefRef))
- val tpt = readTreeRef()
- val rhs = readTreeRef()
- DefDef(mods, name.toTermName, tparams, vparamss, tpt, rhs)
-
- case TYPEDEFtree =>
- setSymModsName()
- val rhs = readTreeRef()
- val tparams = until(end, readTypeDefRef)
- TypeDef(mods, name.toTypeName, tparams, rhs)
-
- case LABELtree =>
- setSymName()
- val rhs = readTreeRef()
- val params = until(end, readIdentRef)
- LabelDef(name.toTermName, params, rhs)
-
- case IMPORTtree =>
- setSym()
- val expr = readTreeRef()
- val selectors = until(end, () => {
- val from = readNameRef()
- val to = readNameRef()
- ImportSelector(from, -1, to, -1)
- })
-
- Import(expr, selectors)
-
- case TEMPLATEtree =>
- setSym()
- val parents = times(readNat(), readTreeRef)
- val self = readValDefRef()
- val body = until(end, readTreeRef)
-
- Template(parents, self, body)
-
- case BLOCKtree =>
- val expr = readTreeRef()
- val stats = until(end, readTreeRef)
- Block(stats, expr)
-
- case CASEtree =>
- val pat = readTreeRef()
- val guard = readTreeRef()
- val body = readTreeRef()
- CaseDef(pat, guard, body)
-
- case ALTERNATIVEtree =>
- Alternative(until(end, readTreeRef))
-
- case STARtree =>
- Star(readTreeRef())
-
- case BINDtree =>
- setSymName()
- Bind(name, readTreeRef())
-
- case UNAPPLYtree =>
- val fun = readTreeRef()
- val args = until(end, readTreeRef)
- UnApply(fun, args)
-
- case ARRAYVALUEtree =>
- val elemtpt = readTreeRef()
- val trees = until(end, readTreeRef)
- ArrayValue(elemtpt, trees)
-
- case FUNCTIONtree =>
- setSym()
- val body = readTreeRef()
- val vparams = until(end, readValDefRef)
- Function(vparams, body)
-
- case ASSIGNtree =>
- val lhs = readTreeRef()
- val rhs = readTreeRef()
- Assign(lhs, rhs)
-
- case IFtree =>
- val cond = readTreeRef()
- val thenp = readTreeRef()
- val elsep = readTreeRef()
- If(cond, thenp, elsep)
-
- case MATCHtree =>
- val selector = readTreeRef()
- val cases = until(end, readCaseDefRef)
- Match(selector, cases)
-
- case RETURNtree =>
- setSym()
- Return(readTreeRef())
-
- case TREtree =>
- val block = readTreeRef()
- val finalizer = readTreeRef()
- val catches = until(end, readCaseDefRef)
- Try(block, catches, finalizer)
-
- case THROWtree =>
- Throw(readTreeRef())
-
- case NEWtree =>
- New(readTreeRef())
-
- case TYPEDtree =>
- val expr = readTreeRef()
- val tpt = readTreeRef()
- Typed(expr, tpt)
-
- case TYPEAPPLYtree =>
- val fun = readTreeRef()
- val args = until(end, readTreeRef)
- TypeApply(fun, args)
-
- case APPLYtree =>
- val fun = readTreeRef()
- val args = until(end, readTreeRef)
- if (fun.symbol.isOverloaded) {
- fun.setType(fun.symbol.info)
- inferMethodAlternative(fun, args map (_.tpe), tpe)
- }
- Apply(fun, args)
-
- case APPLYDYNAMICtree =>
- setSym()
- val qual = readTreeRef()
- val args = until(end, readTreeRef)
- ApplyDynamic(qual, args)
-
- case SUPERtree =>
- setSym()
- val qual = readTreeRef()
- val mix = readTypeNameRef()
- Super(qual, mix)
-
- case THIStree =>
- setSym()
- This(readTypeNameRef())
-
- case SELECTtree =>
- setSym()
- val qualifier = readTreeRef()
- val selector = readNameRef()
- Select(qualifier, selector)
-
- case IDENTtree =>
- setSymName()
- Ident(name)
-
- case LITERALtree =>
- Literal(readConstantRef())
-
- case TYPEtree =>
- TypeTree()
-
- case ANNOTATEDtree =>
- val annot = readTreeRef()
- val arg = readTreeRef()
- Annotated(annot, arg)
-
- case SINGLETONTYPEtree =>
- SingletonTypeTree(readTreeRef())
-
- case SELECTFROMTYPEtree =>
- val qualifier = readTreeRef()
- val selector = readTypeNameRef()
- SelectFromTypeTree(qualifier, selector)
-
- case COMPOUNDTYPEtree =>
- CompoundTypeTree(readTemplateRef())
-
- case APPLIEDTYPEtree =>
- val tpt = readTreeRef()
- val args = until(end, readTreeRef)
- AppliedTypeTree(tpt, args)
-
- case TYPEBOUNDStree =>
- val lo = readTreeRef()
- val hi = readTreeRef()
- TypeBoundsTree(lo, hi)
-
- case EXISTENTIALTYPEtree =>
- val tpt = readTreeRef()
- val whereClauses = until(end, readTreeRef)
- ExistentialTypeTree(tpt, whereClauses)
+ val tpe = readTypeRef()
+ val sym = if (isTreeSymbolPickled(tag)) readSymbolRef() else null
+ val result = readTree(tpe)
- case _ =>
- noSuchTreeTag(tag, end)
- }
+ if (sym ne null) result setSymbol sym
+ result setType tpe
+ }
- if (symbol == null) t setType tpe
- else t setSymbol symbol setType tpe
+ /* Read an abstract syntax tree */
+ protected def readTree(): Tree = {
+ expect(TREE, "tree expected")
+ val end = readEnd()
+ readByte() match {
+ case EMPTYtree => EmptyTree
+ case tag => readNonEmptyTree(tag, end)
+ }
}
def noSuchTreeTag(tag: Int, end: Int) =
@@ -764,7 +587,8 @@ abstract class UnPickler {
val tag = readNat()
if (tag != MODIFIERS)
errorBadSignature("expected a modifiers tag (" + tag + ")")
- val end = readNat() + readIndex
+
+ readEnd()
val pflagsHi = readNat()
val pflagsLo = readNat()
val pflags = (pflagsHi.toLong << 32) + pflagsLo
@@ -796,7 +620,6 @@ abstract class UnPickler {
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 {
@@ -828,6 +651,12 @@ abstract class UnPickler {
case other =>
errorBadSignature("expected an TypeDef (" + other + ")")
}
+ protected def readMemberDefRef(): MemberDef =
+ readTreeRef() match {
+ case tree:MemberDef => tree
+ case other =>
+ errorBadSignature("expected an MemberDef (" + other + ")")
+ }
protected def errorBadSignature(msg: String) =
throw new RuntimeException("malformed Scala signature of " + classRoot.name + " at " + readIndex + "; " + msg)
@@ -843,7 +672,6 @@ abstract class UnPickler {
* error reporting, so we rely on the typechecker to report the error).
*/
def toTypeError(e: MissingRequirementError) = {
- // e.printStackTrace()
new TypeError(e.msg)
}
@@ -851,15 +679,20 @@ abstract class UnPickler {
private class LazyTypeRef(i: Int) extends LazyType with FlagAgnosticCompleter {
private val definedAtRunId = currentRunId
private val p = phase
- override def complete(sym: Symbol) : Unit = try {
+ protected def completeInternal(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 (p ne null)
+ slowButSafeEnteringPhase(p) (sym setInfo tp)
if (currentRunId != definedAtRunId)
sym.setInfo(adaptToNewRunMap(tp))
}
catch {
case e: MissingRequirementError => throw toTypeError(e)
}
+ override def complete(sym: Symbol) : Unit = {
+ completeInternal(sym)
+ if (!isCompilerUniverse) markAllCompleted(sym)
+ }
override def load(sym: Symbol) { complete(sym) }
}
@@ -867,11 +700,12 @@ abstract class UnPickler {
* 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)
+ override def completeInternal(sym: Symbol) = try {
+ super.completeInternal(sym)
+
var alias = at(j, readSymbol)
if (alias.isOverloaded)
- alias = atPhase(picklerPhase)((alias suchThat (alt => sym.tpe =:= sym.owner.thisType.memberType(alt))))
+ alias = slowButSafeEnteringPhase(picklerPhase)((alias suchThat (alt => sym.tpe =:= sym.owner.thisType.memberType(alt))))
sym.asInstanceOf[TermSymbol].setAlias(alias)
}
diff --git a/src/reflect/scala/reflect/internal/settings/AbsSettings.scala b/src/reflect/scala/reflect/internal/settings/AbsSettings.scala
index a6fb4187ca..859f703d97 100644
--- a/src/reflect/scala/reflect/internal/settings/AbsSettings.scala
+++ b/src/reflect/scala/reflect/internal/settings/AbsSettings.scala
@@ -3,7 +3,8 @@
* @author Paul Phillips
*/
-package scala.reflect.internal
+package scala
+package reflect.internal
package settings
/** A Settings abstraction boiled out of the original highly mutable Settings
diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
index 81368df7a6..a494c7f0d0 100644
--- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
+++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
@@ -4,7 +4,8 @@
*/
// $Id$
-package scala.reflect.internal
+package scala
+package reflect.internal
package settings
/** A mutable Settings object.
@@ -32,19 +33,32 @@ abstract class MutableSettings extends AbsSettings {
}
}
- def overrideObjects: BooleanSetting
- def printtypes: BooleanSetting
+ def Xexperimental: BooleanSetting
+ def XfullLubs: BooleanSetting
+ def XnoPatmatAnalysis: BooleanSetting
+ def Xprintpos: BooleanSetting
+ def strictInference: BooleanSetting
+ def Yposdebug: BooleanSetting
+ def Yrangepos: BooleanSetting
+ def Yshowsymowners: BooleanSetting
+ def Yshowsymkinds: BooleanSetting
+ def breakCycles: BooleanSetting
def debug: BooleanSetting
- def Ynotnull: BooleanSetting
+ def developer: BooleanSetting
def explaintypes: BooleanSetting
- def verbose: BooleanSetting
+ def overrideObjects: BooleanSetting
+ def printtypes: BooleanSetting
def uniqid: BooleanSetting
- def Yshowsymkinds: BooleanSetting
- def Xprintpos: BooleanSetting
+ def verbose: BooleanSetting
+
def Yrecursion: IntSetting
def maxClassfileName: IntSetting
- def Xexperimental: BooleanSetting
- def XoldPatmat: BooleanSetting
- def XnoPatmatAnalysis: BooleanSetting
- def XfullLubs: BooleanSetting
+
+ def isScala211: Boolean
+}
+
+object MutableSettings {
+ import scala.language.implicitConversions
+ /** Support the common use case, `if (settings.debug) println("Hello, martin.")` */
+ @inline implicit def reflectSettingToBoolean(s: MutableSettings#BooleanSetting): Boolean = s.value
}
diff --git a/src/reflect/scala/reflect/internal/tpe/CommonOwners.scala b/src/reflect/scala/reflect/internal/tpe/CommonOwners.scala
new file mode 100644
index 0000000000..f879960407
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/tpe/CommonOwners.scala
@@ -0,0 +1,51 @@
+package scala
+package reflect
+package internal
+package tpe
+
+private[internal] trait CommonOwners {
+ self: SymbolTable =>
+
+ /** The most deeply nested owner that contains all the symbols
+ * of thistype or prefixless typerefs/singletype occurrences in given type.
+ */
+ protected[internal] 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.
+ */
+ protected[internal] 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
+}
diff --git a/src/reflect/scala/reflect/internal/tpe/FindMembers.scala b/src/reflect/scala/reflect/internal/tpe/FindMembers.scala
new file mode 100644
index 0000000000..de54f3768e
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/tpe/FindMembers.scala
@@ -0,0 +1,288 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2014 LAMP/EPFL
+ * @author Jason Zaugg
+ */
+package scala.reflect.internal
+package tpe
+
+import Flags._
+import util.Statistics
+import TypesStats._
+
+trait FindMembers {
+ this: SymbolTable =>
+
+ /** Implementatation of `Type#{findMember, findMembers}` */
+ private[internal] abstract class FindMemberBase[T](tpe: Type, name: Name, excludedFlags: Long, requiredFlags: Long) {
+ protected val initBaseClasses: List[Symbol] = tpe.baseClasses
+
+ // The first base class, or the symbol of the ThisType
+ // e.g in:
+ // trait T { self: C => }
+ //
+ // The selector class of `T.this.type` is `T`, and *not* the first base class, `C`.
+ private[this] var _selectorClass: Symbol = null
+ private def selectorClass: Symbol = {
+ if (_selectorClass eq null) {
+ _selectorClass = tpe match {
+ case tt: ThisType => tt.sym // SI-7507 the first base class is not necessarily the selector class.
+ case _ => initBaseClasses.head
+ }
+ }
+ _selectorClass
+ }
+
+ // Cache for the narrowed type of `tp` (in `tp.findMember`).
+ // This is needed to avoid mismatched existential types are reported in SI-5330.
+ private[this] var _self: Type = null
+ protected def self: Type = {
+ // TODO: use narrow only for modules? (correct? efficiency gain?) (<-- Note: this comment predates SI-5330)
+ if (_self eq null) _self = narrowForFindMember(tpe)
+ _self
+ }
+
+ // Main entry point
+ def apply(): T = {
+ if (Statistics.canEnable) Statistics.incCounter(findMemberCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, findMemberNanos) else null
+ try searchConcreteThenDeferred
+ finally if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
+ }
+
+ protected def result: T
+
+ // SLS 5.1.3 First, a concrete definition always overrides an abstract definition
+ private def searchConcreteThenDeferred: T = {
+ val deferredSeen = walkBaseClasses(requiredFlags, excludedFlags | DEFERRED)
+ if (deferredSeen) // OPT: the `if` avoids a second pass if the first pass didn't spot any candidates.
+ walkBaseClasses(requiredFlags | DEFERRED, excludedFlags & ~(DEFERRED.toLong))
+ result
+ }
+
+ /*
+ * Walk up through the decls of each base class.
+ *
+ * Called in two passes: first excluding deferred, then mandating it.
+ *
+ * @return if a potential deferred member was seen on the first pass that calls for a second pass,
+ and `excluded & DEFERRED != 0L`
+ */
+ private def walkBaseClasses(required: Long, excluded: Long): Boolean = {
+ var bcs = initBaseClasses
+
+ // Have we seen a candidate deferred member?
+ var deferredSeen = false
+
+ // All direct parents of refinement classes in the base class sequence
+ // from the current `walkBaseClasses`
+ var refinementParents: List[Symbol] = Nil
+
+ // Has the current `walkBaseClasses` encountered a non-refinement class?
+ var seenFirstNonRefinementClass = false
+
+ val findAll = name == nme.ANYname
+
+ while (!bcs.isEmpty) {
+ val currentBaseClass = bcs.head
+ val decls = currentBaseClass.info.decls
+ var entry = if (findAll) decls.elems else decls.lookupEntry(name)
+ while (entry ne null) {
+ val sym = entry.sym
+ val flags = sym.flags
+ val meetsRequirements = (flags & required) == required
+ if (meetsRequirements) {
+ val excl: Long = flags & excluded
+ val isExcluded: Boolean = excl != 0L
+ if (!isExcluded && isPotentialMember(sym, flags, currentBaseClass, seenFirstNonRefinementClass, refinementParents)) {
+ if (shortCircuit(sym)) return false
+ else addMemberIfNew(sym)
+ } else if (excl == DEFERRED) {
+ deferredSeen = true
+ }
+ }
+ entry = if (findAll) entry.next else decls lookupNextEntry entry
+ }
+
+ // SLS 5.2 The private modifier can be used with any definition or declaration in a template.
+ // They are not inherited by subclasses [...]
+ if (currentBaseClass.isRefinementClass)
+ // SLS 3.2.7 A compound type T1 with . . . with Tn {R } represents objects with members as given in
+ // the component types T1, ..., Tn and the refinement {R }
+ //
+ // => private members should be included from T1, ... Tn. (SI-7475)
+ refinementParents :::= currentBaseClass.parentSymbols
+ else if (currentBaseClass.isClass)
+ seenFirstNonRefinementClass = true // only inherit privates of refinement parents after this point
+
+ bcs = bcs.tail
+ }
+ deferredSeen
+ }
+
+ /* Should this symbol be returned immediately as the sole result? */
+ protected def shortCircuit(sym: Symbol): Boolean
+
+ /* Add this member to the final result, unless an already-found member matches it. */
+ protected def addMemberIfNew(sym: Symbol): Unit
+
+ // Is `sym` a potentially member of `baseClass`?
+ //
+ // Q. When does a potential member fail to be a an actual member?
+ // A. if it is subsumed by an member in a subclass.
+ private def isPotentialMember(sym: Symbol, flags: Long, owner: Symbol,
+ seenFirstNonRefinementClass: Boolean, refinementParents: List[Symbol]): Boolean = {
+ // conservatively (performance wise) doing this with flags masks rather than `sym.isPrivate`
+ // to avoid multiple calls to `Symbol#flags`.
+ val isPrivate = (flags & PRIVATE) == PRIVATE
+ val isPrivateLocal = (flags & PrivateLocal) == PrivateLocal
+
+ // TODO Is the special handling of `private[this]` vs `private` backed up by the spec?
+ def admitPrivate(sym: Symbol): Boolean =
+ (selectorClass == owner) || (
+ !isPrivateLocal // private[this] only a member from within the selector class. (Optimization only? Does the spec back this up?)
+ && (
+ !seenFirstNonRefinementClass
+ || refinementParents.contains(owner)
+ )
+ )
+
+ (!isPrivate || admitPrivate(sym)) && (sym.name != nme.CONSTRUCTOR || owner == initBaseClasses.head)
+ }
+
+ // True unless the already-found member of type `memberType` matches the candidate symbol `other`.
+ protected def isNewMember(member: Symbol, other: Symbol): Boolean =
+ ( (other ne member)
+ && ( (member.owner eq other.owner) // same owner, therefore overload
+ || (member.flags & PRIVATE) != 0 // (unqualified) private members never participate in overriding
+ || (other.flags & PRIVATE) != 0 // ... as overrider or overridee.
+ || !(memberTypeLow(member) matches memberTypeHi(other)) // do the member types match? If so, its an override. Otherwise it's an overload.
+ )
+ )
+
+ // Cache for the member type of a candidate member when comparing against multiple, already-found existing members
+ //
+ // TODO this cache is probably unnecessary, `tp.memberType(sym: MethodSymbol)` is already cached internally.
+ private[this] var _memberTypeHiCache: Type = null
+ private[this] var _memberTypeHiCacheSym: Symbol = null
+
+ protected def memberTypeHi(sym: Symbol): Type = {
+ if (_memberTypeHiCacheSym ne sym) {
+ _memberTypeHiCache = self.memberType(sym)
+ _memberTypeHiCacheSym = sym
+ }
+ _memberTypeHiCache
+ }
+
+ // member type of the LHS of `matches` call. This is an extension point to enable a cache in
+ // FindMember.
+ protected def memberTypeLow(sym: Symbol): Type = self.memberType(sym)
+
+ /** Same as a call to narrow unless existentials are visible
+ * after widening the type. In that case, narrow from the widened
+ * type instead of the proxy. This gives buried existentials a
+ * chance to make peace with the other types. See SI-5330.
+ */
+ private def narrowForFindMember(tp: Type): Type = {
+ val w = tp.widen
+ // Only narrow on widened type when we have to -- narrow is expensive unless the target is a singleton type.
+ if ((tp ne w) && containsExistential(w)) w.narrow
+ else tp.narrow
+ }
+ }
+
+ private[reflect] final class FindMembers(tpe: Type, excludedFlags: Long, requiredFlags: Long)
+ extends FindMemberBase[Scope](tpe, nme.ANYname, excludedFlags, requiredFlags) {
+ private[this] var _membersScope: Scope = null
+ private def membersScope: Scope = {
+ if (_membersScope eq null) _membersScope = newFindMemberScope
+ _membersScope
+ }
+
+ protected def shortCircuit(sym: Symbol): Boolean = false
+ protected def result: Scope = membersScope
+
+ protected def addMemberIfNew(sym: Symbol): Unit = {
+ val members = membersScope
+ var others = members.lookupEntry(sym.name)
+ var isNew = true
+ while ((others ne null) && isNew) {
+ val member = others.sym
+ if (!isNewMember(member, sym))
+ isNew = false
+ others = members lookupNextEntry others // next existing member with the same name.
+ }
+ if (isNew) members.enter(sym)
+ }
+ }
+
+ private[reflect] final class FindMember(tpe: Type, name: Name, excludedFlags: Long, requiredFlags: Long, stableOnly: Boolean)
+ extends FindMemberBase[Symbol](tpe, name, excludedFlags, requiredFlags) {
+ // Gathering the results into a hand rolled ListBuffer
+ // TODO Try just using a ListBuffer to see if this low-level-ness is worth it.
+ private[this] var member0: Symbol = NoSymbol
+ private[this] var members: List[Symbol] = null
+ private[this] var lastM: ::[Symbol] = null
+
+ private def clearAndAddResult(sym: Symbol): Unit = {
+ member0 = sym
+ members = null
+ lastM = null
+ }
+
+ protected def shortCircuit(sym: Symbol): Boolean = (name.isTypeName || (stableOnly && sym.isStable && !sym.hasVolatileType)) && {
+ clearAndAddResult(sym)
+ true
+ }
+
+ protected def addMemberIfNew(sym: Symbol): Unit =
+ if (member0 eq NoSymbol) {
+ member0 = sym // The first found member
+ } else if (members eq null) {
+ // We've found exactly one member so far...
+ if (isNewMember(member0, sym)) {
+ // ... make that two.
+ lastM = new ::(sym, null)
+ members = member0 :: lastM
+ }
+ } else {
+ // Already found 2 or more members
+ var ms: List[Symbol] = members
+
+ var isNew = true
+ while ((ms ne null) && isNew) {
+ val member = ms.head
+ if (!isNewMember(member, sym))
+ isNew = false
+ ms = ms.tail
+ }
+ if (isNew) {
+ val lastM1 = new ::(sym, null)
+ lastM.tl = lastM1
+ lastM = lastM1
+ }
+ }
+
+ // Cache for the member type of the first member we find.
+ private[this] var _member0Tpe: Type = null
+ private[this] def member0Tpe: Type = {
+ assert(member0 != null)
+ if (_member0Tpe eq null) _member0Tpe = self.memberType(member0)
+ _member0Tpe
+ }
+
+ override protected def memberTypeLow(sym: Symbol): Type =
+ if (sym eq member0) member0Tpe else super.memberTypeLow(sym)
+
+ // Assemble the result from the hand-rolled ListBuffer
+ protected def result: Symbol = if (members eq null) {
+ if (member0 == NoSymbol) {
+ if (Statistics.canEnable) Statistics.incCounter(noMemberCount)
+ NoSymbol
+ } else member0
+ } else {
+ if (Statistics.canEnable) Statistics.incCounter(multMemberCount)
+ lastM.tl = Nil
+ initBaseClasses.head.newOverloaded(tpe, members)
+ }
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala
new file mode 100644
index 0000000000..876685e24a
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala
@@ -0,0 +1,611 @@
+package scala
+package reflect
+package internal
+package tpe
+
+import scala.collection.mutable
+import scala.annotation.tailrec
+import util.Statistics
+import Variance._
+
+private[internal] trait GlbLubs {
+ self: SymbolTable =>
+ import definitions._
+ import TypesStats._
+
+ private final val printLubs = scala.sys.props contains "scalac.debug.lub"
+ private final val strictInference = settings.strictInference
+
+ /** In case anyone wants to turn off lub verification without reverting anything. */
+ private final val verifyLubs = true
+
+ private def printLubMatrix(btsMap: Map[Type, List[Type]], depth: Depth) {
+ 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)), left = 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
+ }
+ }
+
+ // only called when strictInference
+ private def willViolateRecursiveBounds(tp: Type, ts: List[Type], tsElimSub: List[Type]) = {
+ val typeSym = ts.head.typeSymbol // we're uniform, the `.head` is as good as any.
+ def fbounds = findRecursiveBounds(ts) map (_._2)
+ def isRecursive = typeSym.typeParams exists fbounds.contains
+
+ isRecursive && (transposeSafe(tsElimSub map (_.normalize.typeArgs)) match {
+ case Some(arggsTransposed) =>
+ val mergedTypeArgs = (tp match { case et: ExistentialType => et.underlying; case _ => tp}).typeArgs
+ exists3(typeSym.typeParams, mergedTypeArgs, arggsTransposed) {
+ (param, arg, lubbedArgs) =>
+ val isExistential = arg.typeSymbol.isExistentiallyBound
+ val isInFBound = fbounds contains param
+ val wasLubbed = !lubbedArgs.exists(_ =:= arg)
+ (!isExistential && isInFBound && wasLubbed)
+ }
+ case None => false
+ })
+ }
+
+ /** 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.
+ */
+ def lubList(ts: List[Type], depth: Depth): List[Type] = {
+ var lubListDepth = Depth.Zero
+ // This catches some recursive situations which would otherwise
+ // befuddle us, e.g. pos/hklub0.scala
+ def isHotForTs(xs: List[Type]) = ts exists (_.typeParams == xs.map(_.typeSymbol))
+
+ def elimHigherOrderTypeParam(tp: Type) = tp match {
+ case TypeRef(_, _, args) if args.nonEmpty && isHotForTs(args) =>
+ logResult("Retracting dummies from " + tp + " in lublist")(tp.typeConstructor)
+ case _ => tp
+ }
+ // pretypes is a tail-recursion-preserving accumulator.
+ @tailrec
+ def loop(pretypes: List[Type], tsBts: List[List[Type]]): List[Type] = {
+ lubListDepth = lubListDepth.incr
+
+ if (tsBts.isEmpty || (tsBts exists typeListIsEmpty)) pretypes.reverse
+ else if (tsBts.tail.isEmpty) pretypes.reverse ++ 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 regarding 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) {
+ val tails = tsBts map (_.tail)
+ val ts1 = elimSub(ts0, depth) map elimHigherOrderTypeParam
+ mergePrefixAndArgs(ts1, Covariant, depth) match {
+ case NoType => loop(pretypes, tails)
+ case tp if strictInference && willViolateRecursiveBounds(tp, ts0, ts1) =>
+ log(s"Breaking recursion in lublist, advancing frontier and discaring merged prefix/args from $tp")
+ loop(pretypes, tails)
+ case tp =>
+ loop(tp :: pretypes, 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(pretypes, newtps)
+ }
+ }
+ }
+
+ val initialBTSes = ts map (_.baseTypeSeq.toList)
+ if (printLubs)
+ printLubMatrix((ts zip initialBTSes).toMap, depth)
+
+ loop(Nil, initialBTSes)
+ }
+
+ /** The minimal symbol of a list of types (as determined by `Symbol.isLess`). */
+ 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 List(t) => List(t)
+ case t :: ts1 =>
+ val rest = elimSuper(ts1 filter (t1 => !(t <:< t1)))
+ if (rest exists (t1 => t1 <:< t)) rest else t :: rest
+ }
+
+ /** 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: Depth): List[Type] = {
+ def elimSub0(ts: List[Type]): List[Type] = ts match {
+ case List() => List()
+ case List(t) => List(t)
+ case t :: ts1 =>
+ val rest = elimSub0(ts1 filter (t1 => !isSubType(t1, t, depth.decr)))
+ if (rest exists (t1 => isSubType(t, t1, depth.decr))) rest else t :: rest
+ }
+ val ts0 = elimSub0(ts)
+ if (ts0.isEmpty || ts0.tail.isEmpty) ts0
+ else {
+ val ts1 = ts0 mapConserve (t => elimAnonymousClass(t.dealiasWiden))
+ 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): Type = tp match {
+ case ExistentialType(_, res) =>
+ res
+ case tv@TypeVar(_, constr) =>
+ if (tv.instValid) stripType(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)
+ }
+
+ /** Does this set of types have the same weak lub as
+ * it does regular lub? This is exposed so lub callers
+ * can discover whether the trees they are typing will
+ * may require further adaptation. It may return false
+ * negatives, but it will not return false positives.
+ */
+ def sameWeakLubAsLub(tps: List[Type]) = tps match {
+ case Nil => true
+ case tp :: Nil => !typeHasAnnotations(tp)
+ case tps => !(tps exists typeHasAnnotations) && !(tps forall isNumericValueType)
+ }
+
+ /** If the arguments are all numeric value types, the numeric
+ * lub according to the weak conformance spec. If any argument
+ * has type annotations, take the lub of the unannotated type
+ * and call the analyzerPlugin method annotationsLub so it can
+ * be further altered. Otherwise, the regular lub.
+ */
+ def weakLub(tps: List[Type]): Type = (
+ if (tps.isEmpty)
+ NothingTpe
+ else if (tps forall isNumericValueType)
+ numericLub(tps)
+ else if (tps exists typeHasAnnotations)
+ annotationsLub(lub(tps map (_.withoutAnnotations)), tps)
+ else
+ lub(tps)
+ )
+
+ def numericLub(ts: List[Type]) =
+ ts reduceLeft ((t1, t2) =>
+ if (isNumericSubType(t1, t2)) t2
+ else if (isNumericSubType(t2, t1)) t1
+ else IntTpe)
+
+ private val _lubResults = new mutable.HashMap[(Depth, List[Type]), Type]
+ def lubResults = _lubResults
+
+ private val _glbResults = new mutable.HashMap[(Depth, List[Type]), Type]
+ def glbResults = _glbResults
+
+ def lub(ts: List[Type]): Type = ts match {
+ case Nil => NothingTpe
+ case t :: Nil => t
+ case _ =>
+ if (Statistics.canEnable) Statistics.incCounter(lubCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, lubNanos) else null
+ try {
+ val res = lub(ts, lubDepth(ts))
+ // If the number of unapplied type parameters in all incoming
+ // types is consistent, and the lub does not match that, return
+ // the type constructor of the calculated lub instead. This
+ // is because lubbing type constructors tends to result in types
+ // which have been applied to dummies or Nothing.
+ ts.map(_.typeParams.size).distinct match {
+ case x :: Nil if res.typeParams.size != x =>
+ logResult(s"Stripping type args from lub because $res is not consistent with $ts")(res.typeConstructor)
+ case _ =>
+ res
+ }
+ }
+ finally {
+ lubResults.clear()
+ glbResults.clear()
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
+ }
+ }
+
+ /** The least upper bound wrt <:< of a list of types */
+ protected[internal] def lub(ts: List[Type], depth: Depth): Type = {
+ def lub0(ts0: List[Type]): Type = elimSub(ts0, depth) match {
+ case List() => NothingTpe
+ 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 @ (mt @ MethodType(params, _)) :: rest =>
+ MethodType(params, lub0(matchingRestypes(ts, mt.paramTypes)))
+ 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 @ AnnotatedType(annots, tpe) :: rest =>
+ annotationsLub(lub0(ts map (_.withoutAnnotations)), ts)
+ case ts =>
+ lubResults get ((depth, ts)) match {
+ case Some(lubType) =>
+ lubType
+ case None =>
+ lubResults((depth, ts)) = AnyTpe
+ val res = if (depth.isNegative) AnyTpe 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.isZero ) 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)
+ || sym.isFinal
+ || 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, depth.decr))
+ 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), depth.decr), lub(bnds map (_.hi), depth.decr))
+ 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, depth)))
+ }
+ // 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 lubsym(sym) andAlso (addMember(lubThisType, lubRefined, _, depth))
+ 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 =>
+ isSubType(t, lubRefined, depth) || {
+ if (settings.debug || 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
+ }
+ }
+ // dropIllegalStarTypes is a localized fix for SI-6897. We should probably
+ // integrate that transformation at a lower level in master, but lubs are
+ // the likely and maybe only spot they escape, so fixing here for 2.10.1.
+ existentialAbstraction(tparams, dropIllegalStarTypes(lubType))
+ }
+ if (printLubs) {
+ println(indent + "lub of " + ts + " at depth "+depth)//debug
+ indent = indent + " "
+ assert(indent.length <= 100)
+ }
+ if (Statistics.canEnable) Statistics.incCounter(nestedLubCount)
+ val res = lub0(ts)
+ if (printLubs) {
+ indent = indent stripSuffix " "
+ println(indent + "lub of " + ts + " is " + res)//debug
+ }
+ 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 = Depth.Zero
+ private final val globalGlbLimit = Depth(2)
+
+ /** The greatest lower bound of a list of types (as determined by `<:<`). */
+ def glb(ts: List[Type]): Type = elimSuper(ts) match {
+ case List() => AnyTpe
+ case List(t) => t
+ case ts0 =>
+ if (Statistics.canEnable) Statistics.incCounter(lubCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, lubNanos) else null
+ try {
+ glbNorm(ts0, lubDepth(ts0))
+ } finally {
+ lubResults.clear()
+ glbResults.clear()
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
+ }
+ }
+
+ protected[internal] def glb(ts: List[Type], depth: Depth): Type = elimSuper(ts) match {
+ case List() => AnyTpe
+ case List(t) => t
+ case ts0 => glbNorm(ts0, depth)
+ }
+
+ /** The greatest lower bound of a list of types (as determined by `<:<`), which have been normalized
+ * with regard to `elimSuper`. */
+ protected def glbNorm(ts: List[Type], depth: Depth): Type = {
+ def glb0(ts0: List[Type]): Type = ts0 match {
+ case List() => AnyTpe
+ 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 @ (mt @ MethodType(params, _)) :: rest =>
+ MethodType(params, glbNorm(matchingRestypes(ts, mt.paramTypes), 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)) = NothingTpe
+ val res = if (depth.isNegative) NothingTpe 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.isZero) 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, depth.decr)
+ 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), depth.decr)
+ val hi = glb(bnds map (_.bounds.hi), depth.decr)
+ 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 = globalGlbDepth.incr
+ val dss = ts flatMap refinedToDecls
+ for (ds <- dss; sym <- ds.iterator)
+ if (globalGlbDepth < globalGlbLimit && !specializesSym(glbThisType, sym, depth))
+ try {
+ addMember(glbThisType, glbRefined, glbsym(sym), depth)
+ } catch {
+ case ex: NoCommonType =>
+ }
+ } finally {
+ globalGlbDepth = globalGlbDepth.decr
+ }
+ if (glbRefined.decls.isEmpty) glbBase else glbRefined
+ }
+ existentialAbstraction(tparams, glbType)
+ } catch {
+ case GlbFailure =>
+ if (ts forall (t => NullTpe <:< t)) NullTpe
+ else NothingTpe
+ }
+ }
+ // if (settings.debug.value) { println(indent + "glb of " + ts + " at depth "+depth); indent = indent + " " } //DEBUG
+ if (Statistics.canEnable) Statistics.incCounter(nestedLubCount)
+ glb0(ts)
+ // if (settings.debug.value) { indent = indent.substring(0, indent.length() - 2); log(indent + "glb of " + ts + " is " + res) }//DEBUG
+ }
+
+ /** 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 mt @ MethodType(params1, res) if isSameTypes(mt.paramTypes, pts) =>
+ res
+ case NullaryMethodType(res) if pts.isEmpty =>
+ res
+ case _ =>
+ throw new NoCommonType(tps)
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala
new file mode 100644
index 0000000000..f9b10c90be
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala
@@ -0,0 +1,592 @@
+package scala
+package reflect
+package internal
+package tpe
+
+import scala.collection.{ mutable }
+import util.{ Statistics, TriState }
+import scala.annotation.tailrec
+
+trait TypeComparers {
+ self: SymbolTable =>
+ import definitions._
+ import TypesStats._
+
+ private final val LogPendingSubTypesThreshold = TypeConstants.DefaultLogThreshhold
+
+ private val _pendingSubTypes = new mutable.HashSet[SubTypePair]
+ def pendingSubTypes = _pendingSubTypes
+
+ final case class SubTypePair(tp1: Type, tp2: Type) {
+ // SI-8146 we used to implement equality here in terms of pairwise =:=.
+ // But, this was inconsistent with hashCode, which was based on the
+ // Type#hashCode, based on the structure of types, not the meaning.
+ // Now, we use `Type#{equals,hashCode}` as the (consistent) basis for
+ // detecting cycles (aka keeping subtyping decidable.)
+ //
+ // I added a tests to show that we detect the cycle: neg/t8146-no-finitary*
+
+ override def toString = tp1+" <:<? "+tp2
+ }
+
+ private var _subsametypeRecursions: Int = 0
+ def subsametypeRecursions = _subsametypeRecursions
+ def subsametypeRecursions_=(value: Int) = _subsametypeRecursions = value
+
+ private def isUnifiable(pre1: Type, pre2: Type) = (
+ (isEligibleForPrefixUnification(pre1) || isEligibleForPrefixUnification(pre2))
+ && (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) 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 || sym1.owner.hasPackageFlag || phase.erasedTypes || pre1 =:= pre2
+ else
+ (sym1.name == sym2.name) && isUnifiable(pre1, pre2)
+ )
+
+ 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) = !isSameTypeConstructor(tp1, tp2)
+
+ private def isSameTypeConstructor(tr1: TypeRef, tr2: TypeRef): Boolean = (
+ (tr1.sym == tr2.sym)
+ && !isDifferentType(tr1.pre, tr2.pre)
+ )
+ private def isSameTypeConstructor(tp1: Type, tp2: Type): Boolean = (
+ tp1.isInstanceOf[TypeRef]
+ && tp2.isInstanceOf[TypeRef]
+ && isSameTypeConstructor(tp1.asInstanceOf[TypeRef], tp2.asInstanceOf[TypeRef])
+ )
+
+ /** Do `tp1` and `tp2` denote equivalent types? */
+ def isSameType(tp1: Type, tp2: Type): Boolean = try {
+ if (Statistics.canEnable) Statistics.incCounter(sametypeCount)
+ subsametypeRecursions += 1
+ //OPT cutdown on Function0 allocation
+ //was:
+ // undoLog undoUnless {
+ // isSameType1(tp1, tp2)
+ // }
+
+ val before = undoLog.log
+ var result = false
+ try {
+ result = isSameType1(tp1, tp2)
+ }
+ finally if (!result) undoLog.undoTo(before)
+ result
+ }
+ finally {
+ subsametypeRecursions -= 1
+ // XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866)
+ // it doesn't help to keep separate recursion counts for the three methods that now share it
+ // if (subsametypeRecursions == 0) undoLog.clear()
+ }
+
+ // @pre: at least one argument has annotations
+ private def sameAnnotatedTypes(tp1: Type, tp2: Type) = (
+ annotationsConform(tp1, tp2)
+ && annotationsConform(tp2, tp1)
+ && (tp1.withoutAnnotations =:= tp2.withoutAnnotations)
+ )
+ // We flush out any AnnotatedTypes before calling isSameType2 because
+ // unlike most other subclasses of Type, we have to allow for equivalence of any
+ // combination of { tp1, tp2 } { is, is not } an AnnotatedType - this because the
+ // logic of "annotationsConform" is arbitrary and unknown.
+ private def isSameType1(tp1: Type, tp2: Type): Boolean = typeRelationPreCheck(tp1, tp2) match {
+ case state if state.isKnown => state.booleanValue
+ case _ if typeHasAnnotations(tp1) || typeHasAnnotations(tp2) => sameAnnotatedTypes(tp1, tp2)
+ case _ => isSameType2(tp1, tp2)
+ }
+
+ private def isSameHKTypes(tp1: Type, tp2: Type) = (
+ tp1.isHigherKinded
+ && tp2.isHigherKinded
+ && (tp1.normalize =:= tp2.normalize)
+ )
+ private def isSameTypeRef(tr1: TypeRef, tr2: TypeRef) = (
+ equalSymsAndPrefixes(tr1.sym, tr1.pre, tr2.sym, tr2.pre)
+ && (isSameHKTypes(tr1, tr2) || isSameTypes(tr1.args, tr2.args))
+ )
+
+ private def isSameSingletonType(tp1: SingletonType, tp2: SingletonType): Boolean = {
+ // We don't use dealiasWiden here because we are looking for the SAME type,
+ // and widening leads to a less specific type. The logic is along the lines of
+ // dealiasAndFollowUnderlyingAsLongAsTheTypeIsEquivalent. This method is only
+ // called after a surface comparison has failed, so if chaseDealiasedUnderlying
+ // does not produce a type other than tp1 and tp2, return false.
+ @tailrec def chaseDealiasedUnderlying(tp: Type): Type = tp.underlying.dealias match {
+ case next: SingletonType if tp ne next => chaseDealiasedUnderlying(next)
+ case _ => tp
+ }
+ val origin1 = chaseDealiasedUnderlying(tp1)
+ val origin2 = chaseDealiasedUnderlying(tp2)
+ ((origin1 ne tp1) || (origin2 ne tp2)) && (origin1 =:= origin2)
+ }
+
+ private def isSameMethodType(mt1: MethodType, mt2: MethodType) = (
+ isSameTypes(mt1.paramTypes, mt2.paramTypes)
+ && (mt1.resultType =:= mt2.resultType.substSym(mt2.params, mt1.params))
+ && (mt1.isImplicit == mt2.isImplicit)
+ )
+
+ private def equalTypeParamsAndResult(tparams1: List[Symbol], res1: Type, tparams2: List[Symbol], res2: Type) = {
+ def subst(info: Type) = info.substSym(tparams2, tparams1)
+ // corresponds does not check length of two sequences before checking the predicate,
+ // but SubstMap assumes it has been checked (SI-2956)
+ ( sameLength(tparams1, tparams2)
+ && (tparams1 corresponds tparams2)((p1, p2) => methodHigherOrderTypeParamsSameVariance(p1, p2) && p1.info =:= subst(p2.info))
+ && (res1 =:= subst(res2))
+ )
+ }
+
+ // SI-2066 This prevents overrides with incompatible variance in higher order type parameters.
+ private def methodHigherOrderTypeParamsSameVariance(sym1: Symbol, sym2: Symbol) = {
+ def ignoreVariance(sym: Symbol) = !(sym.isHigherOrderTypeParameter && sym.logicallyEnclosingMember.isMethod)
+ !settings.isScala211 || ignoreVariance(sym1) || ignoreVariance(sym2) || sym1.variance == sym2.variance
+ }
+
+ private def methodHigherOrderTypeParamsSubVariance(low: Symbol, high: Symbol) =
+ !settings.isScala211 || methodHigherOrderTypeParamsSameVariance(low, high) || low.variance.isInvariant
+
+ def isSameType2(tp1: Type, tp2: Type): Boolean = {
+ def retry(lhs: Type, rhs: Type) = ((lhs ne tp1) || (rhs ne tp2)) && isSameType(lhs, rhs)
+
+ /* Here we highlight those unfortunate type-like constructs which
+ * are hidden bundles of mutable state, cruising the type system picking
+ * up any type constraints naive enough to get into their hot rods.
+ */
+ def mutateNonTypeConstructs(lhs: Type, rhs: Type) = lhs match {
+ case BoundedWildcardType(bounds) => bounds containsType rhs
+ case tv @ TypeVar(_, _) => tv.registerTypeEquality(rhs, typeVarLHS = lhs eq tp1)
+ case TypeRef(tv @ TypeVar(_, _), sym, _) => tv.registerTypeSelection(sym, rhs)
+ case _ => false
+ }
+ /* SingletonType receives this additional scrutiny because there are
+ * a variety of Types which must be treated as equivalent even if they
+ * arrive in different guises. For instance, object Foo in the following
+ * might appear in (at least) the four given below.
+ *
+ * package pkg { object Foo ; type Bar = Foo.type }
+ *
+ * ModuleClassTypeRef(pkg.type, Foo: ModuleClassSymbol, Nil)
+ * ThisType(Foo: ModuleClassSymbol)
+ * SingleType(pkg.type, Foo: ModuleSymbol)
+ * AliasTypeRef(NoPrefix, sym: AliasSymbol, Nil) where sym.info is one of the above
+ */
+ def sameSingletonType = tp1 match {
+ case tp1: SingletonType => tp2 match {
+ case tp2: SingletonType => isSameSingletonType(tp1, tp2)
+ case _ => false
+ }
+ case _ => false
+ }
+
+ /* Those false cases certainly are ugly. There's a proposed SIP to deuglify it.
+ * https://docs.google.com/a/improving.org/document/d/1onPrzSqyDpHScc9PS_hpxJwa3FlPtthxw-bAuuEe8uA
+ */
+ def sameTypeAndSameCaseClass = tp1 match {
+ case tp1: TypeRef => tp2 match { case tp2: TypeRef => isSameTypeRef(tp1, tp2) ; case _ => false }
+ case tp1: MethodType => tp2 match { case tp2: MethodType => isSameMethodType(tp1, tp2) ; case _ => false }
+ case RefinedType(ps1, decls1) => tp2 match { case RefinedType(ps2, decls2) => isSameTypes(ps1, ps2) && (decls1 isSameScope decls2) ; case _ => false }
+ case SingleType(pre1, sym1) => tp2 match { case SingleType(pre2, sym2) => equalSymsAndPrefixes(sym1, pre1, sym2, pre2) ; case _ => false }
+ case PolyType(ps1, res1) => tp2 match { case PolyType(ps2, res2) => equalTypeParamsAndResult(ps1, res1, ps2, res2) ; case _ => false }
+ case ExistentialType(qs1, res1) => tp2 match { case ExistentialType(qs2, res2) => equalTypeParamsAndResult(qs1, res1, qs2, res2) ; case _ => false }
+ case ThisType(sym1) => tp2 match { case ThisType(sym2) => sym1 == sym2 ; case _ => false }
+ case ConstantType(c1) => tp2 match { case ConstantType(c2) => c1 == c2 ; case _ => false }
+ case NullaryMethodType(res1) => tp2 match { case NullaryMethodType(res2) => res1 =:= res2 ; case _ => false }
+ case TypeBounds(lo1, hi1) => tp2 match { case TypeBounds(lo2, hi2) => lo1 =:= lo2 && hi1 =:= hi2 ; case _ => false }
+ case _ => false
+ }
+
+ ( sameTypeAndSameCaseClass
+ || sameSingletonType
+ || mutateNonTypeConstructs(tp1, tp2)
+ || mutateNonTypeConstructs(tp2, tp1)
+ || retry(normalizePlus(tp1), normalizePlus(tp2))
+ )
+ }
+
+ def isSubType(tp1: Type, tp2: Type, depth: Depth = Depth.AnyDepth): Boolean = try {
+ subsametypeRecursions += 1
+
+ //OPT cutdown on Function0 allocation
+ //was:
+ // 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)
+ // }
+ // }
+
+ val before = undoLog.log
+ var result = false
+
+ try result = { // if subtype test fails, it should not affect constraints on typevars
+ if (subsametypeRecursions >= LogPendingSubTypesThreshold) {
+ val p = new SubTypePair(tp1, tp2)
+ if (pendingSubTypes(p))
+ false // see neg/t8146-no-finitary*
+ else
+ try {
+ pendingSubTypes += p
+ isSubType1(tp1, tp2, depth)
+ } finally {
+ pendingSubTypes -= p
+ }
+ } else {
+ isSubType1(tp1, tp2, depth)
+ }
+ } finally if (!result) undoLog.undoTo(before)
+
+ result
+ } finally {
+ subsametypeRecursions -= 1
+ // XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866)
+ // it doesn't help to keep separate recursion counts for the three methods that now share it
+ // if (subsametypeRecursions == 0) undoLog.clear()
+ }
+
+ /** Check whether the subtype or type equivalence relationship
+ * between the argument is predetermined. Returns a tri-state
+ * value: True means the arguments are always sub/same types,
+ * False means they never are, and Unknown means the caller
+ * will have to figure things out.
+ */
+ private def typeRelationPreCheck(tp1: Type, tp2: Type): TriState = {
+ def isTrue = (
+ (tp1 eq tp2)
+ || isErrorOrWildcard(tp1)
+ || isErrorOrWildcard(tp2)
+ || (tp1 eq NoPrefix) && tp2.typeSymbol.isPackageClass // !! I do not see how this would be warranted by the spec
+ || (tp2 eq NoPrefix) && tp1.typeSymbol.isPackageClass // !! I do not see how this would be warranted by the spec
+ )
+ // isFalse, assuming !isTrue
+ def isFalse = (
+ (tp1 eq NoType)
+ || (tp2 eq NoType)
+ || (tp1 eq NoPrefix)
+ || (tp2 eq NoPrefix)
+ )
+
+ if (isTrue) TriState.True
+ else if (isFalse) TriState.False
+ else TriState.Unknown
+ }
+
+ private def isSubType1(tp1: Type, tp2: Type, depth: Depth): Boolean = typeRelationPreCheck(tp1, tp2) match {
+ case state if state.isKnown => state.booleanValue
+ case _ if typeHasAnnotations(tp1) || typeHasAnnotations(tp2) => annotationsConform(tp1, tp2) && (tp1.withoutAnnotations <:< tp2.withoutAnnotations)
+ case _ => isSubType2(tp1, tp2, depth)
+ }
+
+ private def isPolySubType(tp1: PolyType, tp2: PolyType): Boolean = {
+ val PolyType(tparams1, res1) = tp1
+ val PolyType(tparams2, res2) = tp2
+
+ sameLength(tparams1, tparams2) && {
+ // fast-path: polymorphic method type -- type params cannot be captured
+ val isMethod = tparams1.head.owner.isMethod
+ //@M for an example of why we need to generate fresh symbols otherwise, see neg/tcpoly_ticket2101.scala
+ val substitutes = if (isMethod) tparams1 else cloneSymbols(tparams1)
+ def sub1(tp: Type) = if (isMethod) tp else tp.substSym(tparams1, substitutes)
+ def sub2(tp: Type) = tp.substSym(tparams2, substitutes)
+ def cmp(p1: Symbol, p2: Symbol) = (
+ methodHigherOrderTypeParamsSubVariance(p2, p1)
+ && sub2(p2.info) <:< sub1(p1.info)
+ )
+
+ (tparams1 corresponds tparams2)(cmp) && (sub1(res1) <:< sub2(res2))
+ }
+ }
+ // This is looking for situations such as B.this.x.type <:< B.super.x.type.
+ // If it's a ThisType on the lhs and a SuperType on the right, and they originate
+ // in the same class, and the 'x' in the ThisType has in its override chain
+ // the 'x' in the SuperType, then the types conform.
+ private def isThisAndSuperSubtype(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match {
+ case (SingleType(ThisType(lpre), v1), SingleType(SuperType(ThisType(rpre), _), v2)) => (lpre == rpre) && (v1.overrideChain contains v2)
+ case _ => false
+ }
+
+ // @assume tp1.isHigherKinded || tp2.isHigherKinded
+ def isHKSubType(tp1: Type, tp2: Type, depth: Depth): Boolean = {
+ def isSub(ntp1: Type, ntp2: Type) = (ntp1.withoutAnnotations, ntp2.withoutAnnotations) match {
+ case (TypeRef(_, AnyClass, _), _) => false // avoid some warnings when Nothing/Any are on the other side
+ case (_, TypeRef(_, NothingClass, _)) => false
+ case (pt1: PolyType, pt2: PolyType) => isPolySubType(pt1, pt2) // @assume both .isHigherKinded (both normalized to PolyType)
+ case (_: PolyType, MethodType(ps, _)) if ps exists (_.tpe.isWildcard) => false // don't warn on HasMethodMatching on right hand side
+ case _ => // @assume !(both .isHigherKinded) thus cannot be subtypes
+ def tp_s(tp: Type): String = f"$tp%-20s ${util.shortClassOfInstance(tp)}%s"
+ devWarning(s"HK subtype check on $tp1 and $tp2, but both don't normalize to polytypes:\n tp1=${tp_s(ntp1)}\n tp2=${tp_s(ntp2)}")
+ false
+ }
+
+ ( tp1.typeSymbol == NothingClass // @M Nothing is subtype of every well-kinded type
+ || tp2.typeSymbol == AnyClass // @M Any is supertype of every well-kinded type (@PP: is it? What about continuations plugin?)
+ || isSub(tp1.normalize, tp2.normalize) && annotationsConform(tp1, tp2) // @M! normalize reduces higher-kinded case to PolyType's
+ )
+ }
+
+ /** Does type `tp1` conform to `tp2`? */
+ private def isSubType2(tp1: Type, tp2: Type, depth: Depth): Boolean = {
+ def retry(lhs: Type, rhs: Type) = ((lhs ne tp1) || (rhs ne tp2)) && isSubType(lhs, rhs, depth)
+
+ if (isSingleType(tp1) && isSingleType(tp2) || isConstantType(tp1) && isConstantType(tp2))
+ return (tp1 =:= tp2) || isThisAndSuperSubtype(tp1, tp2) || retry(tp1.underlying, tp2)
+
+ if (tp1.isHigherKinded || tp2.isHigherKinded)
+ return isHKSubType(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 =>
+ // TODO - dedicate a method to TypeRef/TypeRef subtyping.
+ // These typerefs are pattern matched up and down far more
+ // than is necessary.
+ val sym1 = tr1.sym
+ val sym2 = tr2.sym
+ val pre1 = tr1.pre
+ val pre2 = tr2.pre
+ (((if (sym1 == sym2) phase.erasedTypes || sym1.owner.hasPackageFlag || isSubType(pre1, pre2, depth)
+ 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, depth))
+ ||
+ sym2.isClass && {
+ val base = tr1 baseType sym2
+ (base ne tr1) && isSubType(base, tr2, depth)
+ }
+ ||
+ thirdTryRef(tr1, tr2))
+ case _ =>
+ secondTry
+ }
+ case AnnotatedType(_, _) =>
+ isSubType(tp1.withoutAnnotations, tp2.withoutAnnotations, depth) &&
+ annotationsConform(tp1, tp2)
+ case BoundedWildcardType(bounds) =>
+ isSubType(tp1, bounds.hi, depth)
+ case tv2 @ TypeVar(_, constr2) =>
+ tp1 match {
+ case AnnotatedType(_, _) | BoundedWildcardType(_) =>
+ secondTry
+ case _ =>
+ tv2.registerBound(tp1, isLowerBound = true)
+ }
+ case _ =>
+ secondTry
+ }
+
+ /* Second try, on the left:
+ * - unwrap AnnotatedTypes, BoundedWildcardTypes,
+ * - bind typevars,
+ * - handle existential types by skolemization.
+ */
+ def secondTry = tp1 match {
+ case AnnotatedType(_, _) =>
+ isSubType(tp1.withoutAnnotations, tp2.withoutAnnotations, depth) &&
+ annotationsConform(tp1, tp2)
+ case BoundedWildcardType(bounds) =>
+ isSubType(tp1.bounds.lo, tp2, depth)
+ case tv @ TypeVar(_,_) =>
+ tv.registerBound(tp2, isLowerBound = false)
+ case ExistentialType(_, _) =>
+ try {
+ skolemizationLevel += 1
+ isSubType(tp1.skolemizeExistential, tp2, depth)
+ } finally {
+ skolemizationLevel -= 1
+ }
+ case _ =>
+ thirdTry
+ }
+
+ def thirdTryRef(tp1: Type, tp2: TypeRef): Boolean = {
+ val sym2 = tp2.sym
+ def retry(lhs: Type, rhs: Type) = isSubType(lhs, rhs, depth)
+ def abstractTypeOnRight(lo: Type) = isDifferentTypeConstructor(tp2, lo) && retry(tp1, lo)
+ def classOnRight = (
+ if (isRawType(tp2)) retry(tp1, rawToExistential(tp2))
+ else if (sym2.isRefinementClass) retry(tp1, sym2.info)
+ else fourthTry
+ )
+ sym2 match {
+ case SingletonClass => tp1.isStable || fourthTry
+ case _: ClassSymbol => classOnRight
+ case _: TypeSymbol if sym2.isDeferred => abstractTypeOnRight(tp2.bounds.lo) || fourthTry
+ case _: TypeSymbol => retry(tp1.normalize, tp2.normalize)
+ case _ => fourthTry
+ }
+ }
+
+ /* Third try, on the right:
+ * - decompose refined types.
+ * - handle typerefs and existentials.
+ * - handle left+right method types, polytypes, typebounds
+ */
+ def thirdTry = tp2 match {
+ case tr2: TypeRef =>
+ thirdTryRef(tp1, tr2)
+ case rt2: RefinedType =>
+ (rt2.parents forall (isSubType(tp1, _, depth))) &&
+ (rt2.decls forall (specializesSym(tp1, _, depth)))
+ case et2: ExistentialType =>
+ et2.withTypeVars(isSubType(tp1, _, depth), depth) || fourthTry
+ 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) &&
+ isSubType(res1.substSym(params1, params2), res2, depth))
+ // 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(_) =>
+ isSubType(pt1.resultType, pt2.resultType, depth)
+ case _ =>
+ false
+ }
+ case TypeBounds(lo2, hi2) =>
+ tp1 match {
+ case TypeBounds(lo1, hi1) =>
+ isSubType(lo2, lo1, depth) && isSubType(hi1, hi2, depth)
+ case _ =>
+ false
+ }
+ case _ =>
+ fourthTry
+ }
+
+ /* Fourth try, on the left:
+ * - handle typerefs, refined types, and singleton types.
+ */
+ def fourthTry = {
+ def retry(lhs: Type, rhs: Type) = isSubType(lhs, rhs, depth)
+ def abstractTypeOnLeft(hi: Type) = isDifferentTypeConstructor(tp1, hi) && retry(hi, tp2)
+
+ tp1 match {
+ case tr1 @ TypeRef(pre1, sym1, _) =>
+ def nullOnLeft = tp2 match {
+ case TypeRef(_, sym2, _) => sym1 isBottomSubClass sym2
+ case _ => isSingleType(tp2) && retry(tp1, tp2.widen)
+ }
+ def moduleOnLeft = tp2 match {
+ case SingleType(pre2, sym2) => equalSymsAndPrefixes(sym1.sourceModule, pre1, sym2, pre2)
+ case _ => false
+ }
+ def classOnLeft = (
+ if (isRawType(tp1)) retry(rawToExistential(tp1), tp2)
+ else if (sym1.isModuleClass) moduleOnLeft
+ else sym1.isRefinementClass && retry(sym1.info, tp2)
+ )
+ sym1 match {
+ case NothingClass => true
+ case NullClass => nullOnLeft
+ case _: ClassSymbol => classOnLeft
+ case _: TypeSymbol if sym1.isDeferred => abstractTypeOnLeft(tp1.bounds.hi)
+ case _: TypeSymbol => retry(tp1.normalize, tp2.normalize)
+ case _ => false
+ }
+ case RefinedType(parents, _) => parents exists (retry(_, tp2))
+ case _: SingletonType => retry(tp1.underlying, tp2)
+ case _ => false
+ }
+ }
+
+ firstTry
+ }
+
+
+ def isWeakSubType(tp1: Type, tp2: Type) =
+ tp1.dealiasWiden match {
+ case TypeRef(_, sym1, _) if isNumericValueClass(sym1) =>
+ tp2.deconst.dealias 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.dealias match {
+ case TypeRef(_, sym2, _) if isNumericValueClass(sym2) =>
+ tv1.registerBound(tp2, isLowerBound = false, isNumericBound = true)
+ case _ =>
+ isSubType(tp1, tp2)
+ }
+ case _ =>
+ isSubType(tp1, tp2)
+ }
+
+ def isNumericSubType(tp1: Type, tp2: Type) = (
+ isNumericSubClass(primitiveBaseClass(tp1.dealiasWiden), primitiveBaseClass(tp2.dealias))
+ )
+
+ /** If the given type has a primitive class among its base classes,
+ * the symbol of that class. Otherwise, NoSymbol.
+ */
+ private def primitiveBaseClass(tp: Type): Symbol = {
+ @tailrec def loop(bases: List[Symbol]): Symbol = bases match {
+ case Nil => NoSymbol
+ case x :: xs => if (isPrimitiveValueClass(x)) x else loop(xs)
+ }
+ loop(tp.baseClasses)
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala
new file mode 100644
index 0000000000..c1c43178e5
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala
@@ -0,0 +1,275 @@
+package scala
+package reflect
+package internal
+package tpe
+
+import scala.collection.{ generic }
+import generic.Clearable
+
+private[internal] trait TypeConstraints {
+ self: SymbolTable =>
+ import definitions._
+
+ /** A log of type variable with their original constraints. Used in order
+ * to undo constraints in the case of isSubType/isSameType failure.
+ */
+ private lazy val _undoLog = new UndoLog
+ def undoLog = _undoLog
+
+ import TypeConstraints.UndoPair
+ class UndoLog extends Clearable {
+ type UndoPairs = List[UndoPair[TypeVar, TypeConstraint]]
+ //OPT this method is public so we can do `manual inlining`
+ var log: UndoPairs = List()
+
+ // register with the auto-clearing cache manager
+ perRunCaches.recordCache(this)
+
+ /** Undo all changes to constraints to type variables upto `limit`. */
+ //OPT this method is public so we can do `manual inlining`
+ def undoTo(limit: UndoPairs) {
+ assertCorrectThread()
+ while ((log ne limit) && log.nonEmpty) {
+ val UndoPair(tv, constr) = log.head
+ tv.constr = constr
+ log = log.tail
+ }
+ }
+
+ /** No sync necessary, because record should only
+ * be called from within an undo or undoUnless block,
+ * which is already synchronized.
+ */
+ private[reflect] def record(tv: TypeVar) = {
+ log ::= UndoPair(tv, tv.constr.cloneInternal)
+ }
+
+ def clear() {
+ if (settings.debug)
+ self.log("Clearing " + log.size + " entries from the undoLog.")
+ log = Nil
+ }
+
+ // `block` should not affect constraints on typevars
+ def undo[T](block: => T): T = {
+ val before = log
+ try block
+ finally undoTo(before)
+ }
+ }
+
+ /** @PP: Unable to see why these apparently constant types should need vals
+ * in every TypeConstraint, I lifted them out.
+ */
+ private lazy val numericLoBound = IntTpe
+ private lazy val numericHiBound = intersectionType(List(ByteTpe, CharTpe), 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 typeIsNothing
+ private var hibounds = hi0 filterNot typeIsAny
+ 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) {
+ // For some reason which is still a bit fuzzy, we must let Nothing through as
+ // a lower bound despite the fact that Nothing is always a lower bound. My current
+ // supposition is that the side-effecting type constraint accumulation mechanism
+ // depends on these subtype tests being performed to make forward progress when
+ // there are mutally recursive type vars.
+ // See pos/t6367 and pos/t6499 for the competing test cases.
+ val mustConsider = tp.typeSymbol match {
+ case NothingClass => true
+ case _ => !(lobounds contains tp)
+ }
+ if (mustConsider) {
+ 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) {
+ // My current test case only demonstrates the need to let Nothing through as
+ // a lower bound, but I suspect the situation is symmetrical.
+ val mustConsider = tp.typeSymbol match {
+ case AnyClass => true
+ case _ => !(hibounds contains tp)
+ }
+ if (mustConsider) {
+ 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 instWithinBounds = instValid && isWithinBounds(inst)
+
+ 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 typeIsNothing match {
+ case Nil => ""
+ case tp :: Nil => " >: " + tp
+ case tps => tps.mkString(" >: (", ", ", ")")
+ }
+ val hi = hiBounds filterNot typeIsAny match {
+ case Nil => ""
+ case tp :: Nil => " <: " + tp
+ case tps => tps.mkString(" <: (", ", ", ")")
+ }
+ lo + hi
+ }
+ if (inst eq NoType) boundsStr
+ else boundsStr + " _= " + inst.safeToString
+ }
+ }
+
+ /** 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[Variance], upper: Boolean, depth: Depth): Boolean = {
+
+ def solveOne(tvar: TypeVar, tparam: Symbol, variance: Variance) {
+ if (tvar.constr.inst == NoType) {
+ val up = if (variance.isContravariant) !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) {
+ debuglog(s"$tvar addHiBound $bound.instantiateTypeParams($tparams, $tvars)")
+ tvar addHiBound bound.instantiateTypeParams(tparams, tvars)
+ }
+ for (tparam2 <- tparams)
+ tparam2.info.bounds.lo.dealias match {
+ case TypeRef(_, `tparam`, _) =>
+ debuglog(s"$tvar addHiBound $tparam2.tpeHK.instantiateTypeParams($tparams, $tvars)")
+ tvar addHiBound tparam2.tpeHK.instantiateTypeParams(tparams, tvars)
+ case _ =>
+ }
+ } else {
+ if (bound.typeSymbol != NothingClass && bound.typeSymbol != tparam) {
+ debuglog(s"$tvar addLoBound $bound.instantiateTypeParams($tparams, $tvars)")
+ tvar addLoBound bound.instantiateTypeParams(tparams, tvars)
+ }
+ for (tparam2 <- tparams)
+ tparam2.info.bounds.hi.dealias match {
+ case TypeRef(_, `tparam`, _) =>
+ debuglog(s"$tvar addLoBound $tparam2.tpeHK.instantiateTypeParams($tparams, $tvars)")
+ 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)))
+ val newInst = (
+ if (up) {
+ if (depth.isAnyDepth) glb(tvar.constr.hiBounds)
+ else glb(tvar.constr.hiBounds, depth)
+ }
+ else {
+ if (depth.isAnyDepth) lub(tvar.constr.loBounds)
+ else lub(tvar.constr.loBounds, depth)
+ }
+ )
+
+ debuglog(s"$tvar setInst $newInst")
+ tvar setInst newInst
+ //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)
+
+ def logBounds(tv: TypeVar) = log {
+ val what = if (!tv.instValid) "is invalid" else s"does not conform to bounds: ${tv.constr}"
+ s"Inferred type for ${tv.originString} (${tv.inst}) $what"
+ }
+
+ tvars forall (tv => tv.instWithinBounds || util.andFalse(logBounds(tv)))
+ }
+}
+
+private[internal] object TypeConstraints {
+ // UndoPair is declared in companion object to not hold an outer pointer reference
+ final case class UndoPair[TypeVar <: SymbolTable#TypeVar,
+ TypeConstraint <: TypeConstraints#TypeConstraint](tv: TypeVar, tConstraint: TypeConstraint)
+}
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala
new file mode 100644
index 0000000000..f06420de96
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala
@@ -0,0 +1,1173 @@
+package scala
+package reflect
+package internal
+package tpe
+
+import scala.collection.{ mutable, immutable }
+import Flags._
+import scala.annotation.tailrec
+import Variance._
+
+private[internal] trait TypeMaps {
+ self: SymbolTable =>
+ import definitions._
+
+ /** Normalize any type aliases within this type (@see Type#normalize).
+ * Note that this depends very much on the call to "normalize", not "dealias",
+ * so it is no longer carries the too-stealthy name "deAlias".
+ */
+ object normalizeAliases extends TypeMap {
+ def apply(tp: Type): Type = mapOver(tp match {
+ case TypeRef(_, sym, _) if sym.isAliasType && tp.isHigherKinded => logResult(s"Normalized type alias function $tp")(tp.normalize)
+ case TypeRef(_, sym, _) if sym.isAliasType => tp.normalize
+ case tp => 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, _) =>
+ AnyTpe
+ case tp1 @ RefinedType(parents, decls) =>
+ parents filter (_.typeSymbol != SingletonClass) match {
+ case Nil => AnyTpe
+ case p :: Nil if decls.isEmpty => mapOver(p)
+ case ps => mapOver(copyRefinedType(tp1, ps, decls))
+ }
+ case tp1 =>
+ mapOver(tp1)
+ }
+ }
+ }
+
+ /** Type with all top-level occurrences of abstract types replaced by their bounds */
+ object abstractTypesToBounds extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case TypeRef(_, sym, _) if sym.isAliasType => apply(tp.dealias)
+ case TypeRef(_, sym, _) if sym.isAbstractType => apply(tp.bounds.hi)
+ case rtp @ RefinedType(parents, decls) => copyRefinedType(rtp, parents mapConserve this, decls)
+ case AnnotatedType(_, _) => mapOver(tp)
+ case _ => tp // no recursion - top level only
+ }
+ }
+
+ // 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
+
+ /** Turn any T* types into Seq[T] except when
+ * in method parameter position.
+ */
+ object dropIllegalStarTypes extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case MethodType(params, restpe) =>
+ // Not mapping over params
+ val restpe1 = apply(restpe)
+ if (restpe eq restpe1) tp
+ else MethodType(params, restpe1)
+ case TypeRef(_, RepeatedParamClass, arg :: Nil) =>
+ seqType(arg)
+ case _ =>
+ if (etaExpandKeepsStar) tp else mapOver(tp)
+ }
+ }
+
+ 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
+ }
+
+ // todo. move these into scala.reflect.api
+
+ /** A prototype for mapping a function over all possible types
+ */
+ abstract class TypeMap(trackVariance: Boolean) extends (Type => Type) {
+ def this() = this(trackVariance = false)
+ def apply(tp: Type): Type
+
+ private[this] var _variance: Variance = if (trackVariance) Covariant else Invariant
+
+ def variance_=(x: Variance) = { assert(trackVariance, this) ; _variance = x }
+ def variance = _variance
+
+ /** 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 = (
+ if (trackVariance && args.nonEmpty && !variance.isInvariant && sym.typeParams.nonEmpty)
+ mapOverArgs(args, sym.typeParams)
+ else
+ 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 = flipped(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 = flipped(mapOver(tparams))
+ val 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 = flipped(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)
+ copyRefinedType(rtp, parents1, decls1)
+ case ExistentialType(tparams, result) =>
+ val tparams1 = mapOver(tparams)
+ val 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 AnnotatedType(annots, atp) =>
+ 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)
+ /*
+ 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);
+ }
+
+ def withVariance[T](v: Variance)(body: => T): T = {
+ val saved = variance
+ variance = v
+ try body finally variance = saved
+ }
+ @inline final def flipped[T](body: => T): T = {
+ if (trackVariance) variance = variance.flip
+ try body
+ finally if (trackVariance) variance = variance.flip
+ }
+ protected def mapOverArgs(args: List[Type], tparams: List[Symbol]): List[Type] = (
+ if (trackVariance)
+ map2Conserve(args, tparams)((arg, tparam) => withVariance(variance * tparam.variance)(this(arg)))
+ else
+ args mapConserve this
+ )
+ /** Applies this map to the symbol's info, setting variance = Invariant
+ * if necessary when the symbol is an alias.
+ */
+ private def applyToSymbolInfo(sym: Symbol): Type = {
+ if (trackVariance && !variance.isInvariant && sym.isAliasType)
+ withVariance(Invariant)(this(sym.info))
+ else
+ this(sym.info)
+ }
+
+ /** Called by mapOver to determine whether the original symbols can
+ * be returned, or whether they must be cloned.
+ */
+ protected def noChangeToSymbols(origSyms: List[Symbol]): Boolean = {
+ @tailrec def loop(syms: List[Symbol]): Boolean = syms match {
+ case Nil => true
+ case x :: xs => (x.info eq applyToSymbolInfo(x)) && loop(xs)
+ }
+ loop(origSyms)
+ }
+
+ /** 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
+ }
+ }
+
+ /** 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) AnyRefTpe
+ else try {
+ expanded += sym
+ val eparams = mapOver(typeParamsToExistentials(sym))
+ existentialAbstraction(eparams, typeRef(apply(pre), sym, eparams map (_.tpe)))
+ } finally {
+ expanded -= sym
+ }
+ case _ =>
+ mapOver(tp)
+ }
+ }
+ /***
+ *@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)
+ }
+ }
+ */
+
+ /** Used by existentialAbstraction.
+ */
+ class ExistentialExtrapolation(tparams: List[Symbol]) extends TypeMap(trackVariance = true) {
+ 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)
+ }
+
+ /** If these conditions all hold:
+ * 1) we are in covariant (or contravariant) position
+ * 2) this type occurs exactly once in the existential scope
+ * 3) the widened upper (or lower) bound of this type contains no references to tparams
+ * Then we replace this lone occurrence of the type with the widened upper (or lower) bound.
+ * All other types pass through unchanged.
+ */
+ def apply(tp: Type): Type = {
+ val tp1 = mapOver(tp)
+ if (variance.isInvariant) tp1
+ else tp1 match {
+ case TypeRef(pre, sym, args) if tparams contains sym =>
+ val repl = if (variance.isPositive) dropSingletonType(tp1.bounds.hi) else tp1.bounds.lo
+ val count = occurCount(sym)
+ val containsTypeParam = tparams exists (repl contains _)
+ def msg = {
+ val word = if (variance.isPositive) "upper" else "lower"
+ s"Widened lone occurrence of $tp1 inside existential to $word bound"
+ }
+ if (!repl.typeSymbol.isBottomClass && count == 1 && !containsTypeParam)
+ debuglogResult(msg)(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)
+ }
+ }
+
+ /** Might the given symbol be important when calculating the prefix
+ * of a type? When tp.asSeenFrom(pre, clazz) is called on `tp`,
+ * the result will be `tp` unchanged if `pre` is trivial and `clazz`
+ * is a symbol such that isPossiblePrefix(clazz) == false.
+ */
+ def isPossiblePrefix(clazz: Symbol) = clazz.isClass && !clazz.isPackageClass
+
+ protected[internal] def skipPrefixOf(pre: Type, clazz: Symbol) = (
+ (pre eq NoType) || (pre eq NoPrefix) || !isPossiblePrefix(clazz)
+ )
+
+ def newAsSeenFromMap(pre: Type, clazz: Symbol): AsSeenFromMap =
+ new AsSeenFromMap(pre, clazz)
+
+ /** A map to compute the asSeenFrom method.
+ */
+ class AsSeenFromMap(seenFromPrefix: Type, seenFromClass: Symbol) extends TypeMap with KeepOnlyTypeConstraints {
+ // Some example source constructs relevant in asSeenFrom:
+ //
+ // object CaptureThis {
+ // trait X[A] { def f: this.type = this }
+ // class Y[A] { def f: this.type = this }
+ // // Created new existential to represent This(CaptureThis.X) seen from CaptureThis.X[B]: type _1.type <: CaptureThis.X[B] with Singleton
+ // def f1[B] = new X[B] { }
+ // // TODO - why is the behavior different when it's a class?
+ // def f2[B] = new Y[B] { }
+ // }
+ // class CaptureVal[T] {
+ // val f: java.util.List[_ <: T] = null
+ // // Captured existential skolem for type _$1 seen from CaptureVal.this.f.type: type _$1
+ // def g = f get 0
+ // }
+ // class ClassParam[T] {
+ // // AsSeenFromMap(Inner.this.type, class Inner)/classParameterAsSeen(T)#loop(ClassParam.this.type, class ClassParam)
+ // class Inner(lhs: T) { def f = lhs }
+ // }
+ def capturedParams: List[Symbol] = _capturedParams
+ def capturedSkolems: List[Symbol] = _capturedSkolems
+
+ def apply(tp: Type): Type = tp match {
+ case tp @ ThisType(_) => thisTypeAsSeen(tp)
+ case tp @ SingleType(_, sym) => if (sym.isPackageClass) tp else singleTypeAsSeen(tp)
+ case tp @ TypeRef(_, sym, _) if isTypeParamOfEnclosingClass(sym) => classParameterAsSeen(tp)
+ case _ => mapOver(tp)
+ }
+
+ private var _capturedSkolems: List[Symbol] = Nil
+ private var _capturedParams: List[Symbol] = Nil
+ private val isStablePrefix = seenFromPrefix.isStable
+
+ // isBaseClassOfEnclosingClassOrInfoIsNotYetComplete would be a more accurate
+ // but less succinct name.
+ private def isBaseClassOfEnclosingClass(base: Symbol) = {
+ def loop(encl: Symbol): Boolean = (
+ isPossiblePrefix(encl)
+ && ((encl isSubClass base) || loop(encl.owner.enclClass))
+ )
+ // The hasCompleteInfo guard is necessary to avoid cycles during the typing
+ // of certain classes, notably ones defined inside package objects.
+ !base.hasCompleteInfo || loop(seenFromClass)
+ }
+
+ /** Is the symbol a class type parameter from one of the enclosing
+ * classes, or a base class of one of them?
+ */
+ private def isTypeParamOfEnclosingClass(sym: Symbol): Boolean = (
+ sym.isTypeParameter
+ && sym.owner.isClass
+ && isBaseClassOfEnclosingClass(sym.owner)
+ )
+
+ /** Creates an existential representing a type parameter which appears
+ * in the prefix of a ThisType.
+ */
+ protected def captureThis(pre: Type, clazz: Symbol): Type = {
+ capturedParams find (_.owner == clazz) match {
+ case Some(p) => p.tpe
+ case _ =>
+ val qvar = clazz freshExistential nme.SINGLETON_SUFFIX setInfo singletonBounds(pre)
+ _capturedParams ::= qvar
+ debuglog(s"Captured This(${clazz.fullNameString}) seen from $seenFromPrefix: ${qvar.defString}")
+ qvar.tpe
+ }
+ }
+ protected def captureSkolems(skolems: List[Symbol]) {
+ for (p <- skolems; if !(capturedSkolems contains p)) {
+ debuglog(s"Captured $p seen from $seenFromPrefix")
+ _capturedSkolems ::= p
+ }
+ }
+
+ /** Find the type argument in an applied type which corresponds to a type parameter.
+ * The arguments are required to be related as follows, through intermediary `clazz`.
+ * An exception will be thrown if this is violated.
+ *
+ * @param lhs its symbol is a type parameter of `clazz`
+ * @param rhs a type application constructed from `clazz`
+ */
+ private def correspondingTypeArgument(lhs: Type, rhs: Type): Type = {
+ val TypeRef(_, lhsSym, lhsArgs) = lhs
+ val TypeRef(_, rhsSym, rhsArgs) = rhs
+ require(lhsSym.owner == rhsSym, s"$lhsSym is not a type parameter of $rhsSym")
+
+ // Find the type parameter position; we'll use the corresponding argument.
+ // Why are we checking by name rather than by equality? Because for
+ // reasons which aren't yet fully clear, we can arrive here holding a type
+ // parameter whose owner is rhsSym, and which shares the name of an actual
+ // type parameter of rhsSym, but which is not among the type parameters of
+ // rhsSym. One can see examples of it at SI-4365.
+ val argIndex = rhsSym.typeParams indexWhere (lhsSym.name == _.name)
+ // don't be too zealous with the exceptions, see #2641
+ if (argIndex < 0 && rhs.parents.exists(typeIsErroneous))
+ ErrorType
+ else {
+ // It's easy to get here when working on hardcore type machinery (not to
+ // mention when not doing so, see above) so let's provide a standout error.
+ def own_s(s: Symbol) = s.nameString + " in " + s.owner.nameString
+ def explain =
+ sm"""| sought ${own_s(lhsSym)}
+ | classSym ${own_s(rhsSym)}
+ | tparams ${rhsSym.typeParams map own_s mkString ", "}
+ |"""
+
+ if (argIndex < 0)
+ abort(s"Something is wrong: cannot find $lhs in applied type $rhs\n" + explain)
+ else {
+ val targ = rhsArgs(argIndex)
+ // @M! don't just replace the whole thing, might be followed by type application
+ val result = appliedType(targ, lhsArgs mapConserve this)
+ def msg = s"Created $result, though could not find ${own_s(lhsSym)} among tparams of ${own_s(rhsSym)}"
+ if (!rhsSym.typeParams.contains(lhsSym))
+ devWarning(s"Inconsistent tparam/owner views: had to fall back on names\n$msg\n$explain")
+
+ result
+ }
+ }
+ }
+
+ // 0) @pre: `classParam` is a class type parameter
+ // 1) Walk the owner chain of `seenFromClass` until we find the class which owns `classParam`
+ // 2) Take the base type of the prefix at that point with respect to the owning class
+ // 3) Solve for the type parameters through correspondence with the type args of the base type
+ //
+ // Only class type parameters (and not skolems) are considered, because other type parameters
+ // are not influenced by the prefix through which they are seen. Note that 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.
+ private def classParameterAsSeen(classParam: Type): Type = {
+ val TypeRef(_, tparam, _) = classParam
+
+ def loop(pre: Type, clazz: Symbol): Type = {
+ // have to deconst because it may be a Class[T]
+ def nextBase = (pre baseType clazz).deconst
+ //@M! see test pos/tcpoly_return_overriding.scala why mapOver is necessary
+ if (skipPrefixOf(pre, clazz))
+ mapOver(classParam)
+ else if (!matchesPrefixAndClass(pre, clazz)(tparam.owner))
+ loop(nextBase.prefix, clazz.owner)
+ else nextBase match {
+ case NoType => loop(NoType, clazz.owner) // backstop for SI-2797, must remove `SingletonType#isHigherKinded` and run pos/t2797.scala to get here.
+ case applied @ TypeRef(_, _, _) => correspondingTypeArgument(classParam, applied)
+ case ExistentialType(eparams, qtpe) => captureSkolems(eparams) ; loop(qtpe, clazz)
+ case t => abort(s"$tparam in ${tparam.owner} cannot be instantiated from ${seenFromPrefix.widen}")
+ }
+ }
+ loop(seenFromPrefix, seenFromClass)
+ }
+
+ // Does the candidate symbol match the given prefix and class?
+ // Since pre may be something like ThisType(A) where trait A { self: B => },
+ // we have to test the typeSymbol of the widened type, not pre.typeSymbol, or
+ // B will not be considered.
+ private def matchesPrefixAndClass(pre: Type, clazz: Symbol)(candidate: Symbol) =
+ (clazz == candidate) && (pre.widen.typeSymbol isSubClass clazz)
+
+ // Whether the annotation tree currently being mapped over has had a This(_) node rewritten.
+ private[this] var wroteAnnotation = false
+ private object annotationArgRewriter extends TypeMapTransformer {
+ private def matchesThis(thiz: Symbol) = matchesPrefixAndClass(seenFromPrefix, seenFromClass)(thiz)
+
+ // what symbol should really be used?
+ private def newThis(): Tree = {
+ wroteAnnotation = true
+ val presym = seenFromPrefix.widen.typeSymbol
+ val thisSym = presym.owner.newValue(presym.name.toTermName, presym.pos) setInfo seenFromPrefix
+ gen.mkAttributedQualifier(seenFromPrefix, thisSym)
+ }
+
+ /** Rewrite `This` trees in annotation argument trees */
+ override def transform(tree: Tree): Tree = super.transform(tree) match {
+ case This(_) if matchesThis(tree.symbol) => newThis()
+ case tree => tree
+ }
+ }
+
+ // This becomes considerably cheaper if we optimize for the common cases:
+ // where the prefix is stable and where no This nodes are rewritten. If
+ // either is true, then we don't need to worry about calling giveup. So if
+ // the prefix is unstable, use a stack variable to indicate whether the tree
+ // was touched. This takes us to one allocation per AsSeenFromMap rather
+ // than an allocation on every call to mapOver, and no extra work when the
+ // tree only has its types remapped.
+ override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = {
+ if (isStablePrefix)
+ annotationArgRewriter transform tree
+ else {
+ val saved = wroteAnnotation
+ wroteAnnotation = false
+ try annotationArgRewriter transform tree
+ finally if (wroteAnnotation) giveup() else wroteAnnotation = saved
+ }
+ }
+
+ private def thisTypeAsSeen(tp: ThisType): Type = {
+ def loop(pre: Type, clazz: Symbol): Type = {
+ val pre1 = pre match {
+ case SuperType(thistpe, _) => thistpe
+ case _ => pre
+ }
+ if (skipPrefixOf(pre, clazz))
+ mapOver(tp) // TODO - is mapOver necessary here?
+ else if (!matchesPrefixAndClass(pre, clazz)(tp.sym))
+ loop((pre baseType clazz).prefix, clazz.owner)
+ else if (pre1.isStable)
+ pre1
+ else
+ captureThis(pre1, clazz)
+ }
+ loop(seenFromPrefix, seenFromClass)
+ }
+
+ private def singleTypeAsSeen(tp: SingleType): Type = {
+ val SingleType(pre, sym) = tp
+
+ 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
+ }
+
+ override def toString = s"AsSeenFromMap($seenFromPrefix, $seenFromClass)"
+ }
+
+ /** A base class to compute all substitutions */
+ abstract class SubstMap[T](from: List[Symbol], to: List[T]) extends TypeMap {
+ // OPT this check was 2-3% of some profiles, demoted to -Xdev
+ if (isDeveloper) 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
+ }
+
+ @tailrec private 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)
+ )
+
+ def apply(tp0: Type): Type = if (from.isEmpty) tp0 else {
+ val boundSyms = tp0.boundSyms
+ val tp1 = if (boundSyms.nonEmpty && (boundSyms exists from.contains)) renameBoundSyms(tp0) else tp0
+ val tp = mapOver(tp1)
+ def substFor(sym: Symbol) = subst(tp, sym, from, to)
+
+ 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) =>
+ val tcon = substFor(sym)
+ if ((tp eq tcon) || args.isEmpty) tcon
+ else appliedType(tcon.typeConstructor, args)
+ case SingleType(NoPrefix, sym) =>
+ substFor(sym)
+ case ClassInfoType(parents, decls, sym) =>
+ val parents1 = parents mapConserve this
+ // We don't touch decls here; they will be touched when an enclosing TreeSubstitutor
+ // transforms the tree that defines them.
+ if (parents1 eq parents) tp
+ else ClassInfoType(parents1, decls, sym)
+ case _ =>
+ tp
+ }
+ }
+ }
+
+ /** A map to implement the `substSym` method. */
+ class SubstSymMap(from: List[Symbol], to: List[Symbol]) extends SubstMap(from, to) {
+ def this(pairs: (Symbol, Symbol)*) = this(pairs.toList.map(_._1), pairs.toList.map(_._2))
+
+ protected def toType(fromtp: Type, sym: Symbol) = fromtp match {
+ case TypeRef(pre, _, args) => copyTypeRef(fromtp, pre, sym, args)
+ case SingleType(pre, _) => singleType(pre, sym)
+ }
+ @tailrec private 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)
+ )
+ private def substFor(sym: Symbol) = subst(sym, from, to)
+
+ override def apply(tp: Type): Type = (
+ if (from.isEmpty) tp
+ else tp match {
+ case TypeRef(pre, sym, args) if pre ne NoPrefix =>
+ val newSym = substFor(sym)
+ // mapOver takes care of subst'ing in args
+ mapOver ( if (sym eq newSym) tp else copyTypeRef(tp, pre, newSym, args) )
+ // assert(newSym.typeParams.length == sym.typeParams.length, "typars mismatch in SubstSymMap: "+(sym, sym.typeParams, newSym, newSym.typeParams))
+ case SingleType(pre, sym) if pre ne NoPrefix =>
+ val newSym = substFor(sym)
+ mapOver( if (sym eq newSym) tp else singleType(pre, newSym) )
+ case _ =>
+ super.apply(tp)
+ }
+ )
+
+ object mapTreeSymbols extends TypeMapTransformer {
+ val strictCopy = newStrictTreeCopier
+
+ def termMapsTo(sym: Symbol) = from indexOf sym match {
+ case -1 => None
+ case idx => Some(to(idx))
+ }
+
+ // if tree.symbol is mapped to another symbol, passes the new symbol into the
+ // constructor `trans` and sets the symbol and the type on the resulting tree.
+ def transformIfMapped(tree: Tree)(trans: Symbol => Tree) = termMapsTo(tree.symbol) match {
+ case Some(toSym) => trans(toSym) setSymbol toSym setType tree.tpe
+ case None => tree
+ }
+
+ // changes trees which refer to one of the mapped symbols. trees are copied before attributes are modified.
+ override def transform(tree: Tree) = {
+ // super.transform maps symbol references in the types of `tree`. it also copies trees where necessary.
+ super.transform(tree) match {
+ case id @ Ident(_) =>
+ transformIfMapped(id)(toSym =>
+ strictCopy.Ident(id, toSym.name))
+
+ case sel @ Select(qual, name) =>
+ transformIfMapped(sel)(toSym =>
+ strictCopy.Select(sel, qual, toSym.name))
+
+ case tree => tree
+ }
+ }
+ }
+ override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = {
+ mapTreeSymbols.transform(tree)
+ }
+ }
+
+ /** A map to implement the `subst` method. */
+ class SubstTypeMap(val from: List[Symbol], val 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.dealias)
+ }
+ }
+
+ object ApproximateDependentMap extends TypeMap {
+ def apply(tp: Type): Type =
+ if (tp.isImmediatelyDependent) WildcardType
+ else mapOver(tp)
+ }
+
+ /** Note: This map is needed even for non-dependent method types, despite what the name might imply.
+ */
+ 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.iterator.filter(_ ne null).toList
+
+ private object StableArgTp {
+ // type of actual arg corresponding to param -- if the type is stable
+ def unapply(param: Symbol): Option[Type] = (params indexOf param) match {
+ case -1 => None
+ case pid =>
+ val tp = actuals(pid)
+ if (tp.isStable && (tp.typeSymbol != NothingClass)) Some(tp)
+ else None
+ }
+ }
+
+ /** Return the type symbol for referencing a parameter that's instantiated to an unstable actual argument.
+ *
+ * To soundly abstract over an unstable value (x: T) while retaining the most type information,
+ * use `x.type forSome { type x.type <: T with Singleton}`
+ * `typeOf[T].narrowExistentially(symbolOf[x])`.
+ *
+ * See also: captureThis in AsSeenFromMap.
+ */
+ private def existentialFor(pid: Int) = {
+ if (existentials(pid) eq null) {
+ val param = params(pid)
+ existentials(pid) = (
+ param.owner.newExistential(param.name.toTypeName append nme.SINGLETON_SUFFIX, param.pos, param.flags)
+ setInfo singletonBounds(actuals(pid))
+ )
+ }
+ existentials(pid)
+ }
+
+ private object UnstableArgTp {
+ // existential quantifier and type of corresponding actual arg with unstable type
+ def unapply(param: Symbol): Option[(Symbol, Type)] = (params indexOf param) match {
+ case -1 => None
+ case pid =>
+ val sym = existentialFor(pid)
+ Some((sym, sym.tpe_*)) // refers to an actual value, must be kind-*
+ }
+ }
+
+ private object StabilizedArgTp {
+ def unapply(param: Symbol): Option[Type] =
+ param match {
+ case StableArgTp(tp) => Some(tp) // (1)
+ case UnstableArgTp(_, tp) => Some(tp) // (2)
+ case _ => None
+ }
+ }
+
+ /** instantiate `param.type` to the (sound approximation of the) type `T`
+ * of the actual argument `arg` that was passed in for `param`
+ *
+ * (1) If `T` is stable, we can just use that.
+ *
+ * (2) SI-3873: it'd be unsound to instantiate `param.type` to an unstable `T`,
+ * so we approximate to `X forSome {type X <: T with Singleton}` -- we can't soundly say more.
+ */
+ def apply(tp: Type): Type = tp match {
+ case SingleType(NoPrefix, StabilizedArgTp(tp)) => tp
+ case _ => mapOver(tp)
+ }
+
+ //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 StableArgTp(tp) => gen.mkAttributedQualifier(tp, tree.symbol)
+ case UnstableArgTp(quant, tp) => Ident(quant) copyAttrs tree setType tp
+ case _ => super.transform(tree)
+ }
+ }
+ treeTrans transform arg
+ }
+ }
+
+ /** 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 each occurrence of a type variable to its origin. */
+ 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 `filter` method. */
+ class FilterTypeCollector(p: Type => Boolean) extends TypeCollector[List[Type]](Nil) {
+ 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)
+ }
+ }
+ }
+
+ 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, stableOnly = true) orElse {
+ if (sym.isAliasType) throw missingAliasException
+ devWarning(s"$pre.$sym no longer exist at 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.hasPackageFlag) 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) {
+ devWarning(s"adapt to new run failed: pre=$pre pre1=$pre1 sym=$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 ExistentialType(_, _) => mapOver(tp)
+ case _ => tp
+ }
+ }
+
+}
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala b/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala
new file mode 100644
index 0000000000..a062fc8209
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala
@@ -0,0 +1,48 @@
+package scala
+package reflect
+package internal
+package tpe
+
+import scala.collection.mutable.HashSet
+
+private[internal] trait TypeToStrings {
+ self: SymbolTable =>
+
+ /** The maximum number of recursions allowed in toString
+ */
+ final val maxToStringRecursions = 50
+
+ private var _toStringRecursions = 0
+ def toStringRecursions = _toStringRecursions
+ def toStringRecursions_=(value: Int) = _toStringRecursions = value
+
+ private var _toStringSubjects = HashSet[Type]()
+ def toStringSubjects = _toStringSubjects
+
+ protected def typeToString(tpe: Type): String =
+ // if (toStringSubjects contains tpe) {
+ // // handles self-referential anonymous classes and who knows what else
+ // "..."
+ // }
+ // else
+ if (toStringRecursions >= maxToStringRecursions) {
+ devWarning("Exceeded recursion depth attempting to print " + util.shortClassOfInstance(tpe))
+ if (settings.debug)
+ (new Throwable).printStackTrace
+
+ "..."
+ }
+ else
+ try {
+ toStringRecursions += 1
+ // TODO: study performance impact of this cache
+ // to quote Jason:
+ // I'm a little uneasy with the performance impact of the fail-safe. We end up calling Type#toString
+ // when we generate error messages, including, importantly, errors issued during silent mode that are never issued.
+ // toStringSubjects += tpe
+ tpe.safeToString
+ } finally {
+ // toStringSubjects -= tpe
+ toStringRecursions -= 1
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala
index 52d1657dc3..d5b5967145 100644
--- a/src/reflect/scala/reflect/internal/transform/Erasure.scala
+++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package internal
package transform
@@ -16,7 +17,7 @@ trait Erasure {
/** 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 {
+ private def genericCore(tp: Type): Type = tp.dealiasWiden 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.
@@ -36,7 +37,7 @@ trait Erasure {
* 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 {
+ def unapply(tp: Type): Option[(Int, Type)] = tp.dealiasWiden match {
case TypeRef(_, ArrayClass, List(arg)) =>
genericCore(arg) match {
case NoType =>
@@ -54,9 +55,13 @@ trait Erasure {
}
}
+ /** Arrays despite their finality may turn up as refined type parents,
+ * e.g. with "tagged types" like Array[Int] with T.
+ */
protected def unboundedGenericArrayLevel(tp: Type): Int = tp match {
- case GenericArray(level, core) if !(core <:< AnyRefClass.tpe) => level
- case _ => 0
+ case GenericArray(level, core) if !(core <:< AnyRefTpe) => level
+ case RefinedType(ps, _) if ps.nonEmpty => logResult(s"Unbounded generic level for $tp is")((ps map unboundedGenericArrayLevel).max)
+ case _ => 0
}
// @M #2585 when generating a java generic signature that includes
@@ -68,17 +73,8 @@ trait Erasure {
// 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 unboxDerivedValueClassMethod(clazz: Symbol): Symbol =
- (clazz.info.decl(nme.unbox)) orElse
- (clazz.info.decls.find(_ hasAllFlags PARAMACCESSOR | METHOD) getOrElse
- NoSymbol)
-
- def underlyingOfValueClass(clazz: Symbol): Type =
- clazz.derivedValueClassUnbox.tpe.resultType
+ protected def rebindInnerClass(pre: Type, cls: Symbol): Type =
+ if (cls.isTopLevel || cls.isLocalToBlock) pre else cls.owner.tpe_*
/** The type of the argument of a value class reference after erasure
* This method needs to be called at a phase no later than erasurephase
@@ -101,36 +97,40 @@ trait Erasure {
def valueClassIsParametric(clazz: Symbol): Boolean = {
assert(!phase.erasedTypes)
clazz.typeParams contains
- clazz.derivedValueClassUnbox.tpe.resultType.normalize.typeSymbol
+ clazz.derivedValueClassUnbox.tpe.resultType.typeSymbol
}
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
+ def eraseNormalClassRef(tref: TypeRef): Type = {
+ val TypeRef(pre, clazz, args) = tref
+ val pre1 = apply(rebindInnerClass(pre, clazz))
+ val args1 = Nil
+ if ((pre eq pre1) && (args eq args1)) tref // OPT
+ else typeRef(pre1, clazz, args1) // #2585
+ }
protected def eraseDerivedValueClassRef(tref: TypeRef): Type = erasedValueClassArg(tref)
def apply(tp: Type): Type = tp match {
case ConstantType(_) =>
tp
+ case st: ThisType if st.sym.isPackageClass =>
+ tp
case st: SubType =>
apply(st.supertype)
case tref @ TypeRef(pre, sym, args) =>
if (sym == ArrayClass)
- if (unboundedGenericArrayLevel(tp) == 1) ObjectClass.tpe
- else if (args.head.typeSymbol.isBottomClass) ObjectArray
+ if (unboundedGenericArrayLevel(tp) == 1) ObjectTpe
+ else if (args.head.typeSymbol.isBottomClass) arrayType(ObjectTpe)
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 == AnyClass || sym == AnyValClass || sym == SingletonClass) ObjectTpe
+ else if (sym == UnitClass) BoxedUnitTpe
else if (sym.isRefinementClass) apply(mergeParents(tp.parents))
else if (sym.isDerivedValueClass) eraseDerivedValueClassRef(tref)
- else if (sym.isClass) eraseNormalClassRef(pre, sym)
- else apply(sym.info) // alias type or abstract type
+ else if (sym.isClass) eraseNormalClassRef(tref)
+ else apply(sym.info asSeenFrom (pre, sym.owner)) // alias type or abstract type
case PolyType(tparams, restpe) =>
apply(restpe)
case ExistentialType(tparams, restpe) =>
@@ -138,18 +138,18 @@ trait Erasure {
case mt @ MethodType(params, restpe) =>
MethodType(
cloneSymbolsAndModify(params, ErasureMap.this),
- if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass)
+ if (restpe.typeSymbol == UnitClass) UnitTpe
// 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(mt.paramTypes)))
case RefinedType(parents, decls) =>
apply(mergeParents(parents))
- case AnnotatedType(_, atp, _) =>
+ case AnnotatedType(_, atp) =>
apply(atp)
case ClassInfoType(parents, decls, clazz) =>
ClassInfoType(
if (clazz == ObjectClass || isPrimitiveValueClass(clazz)) Nil
- else if (clazz == ArrayClass) List(ErasedObject)
+ else if (clazz == ArrayClass) ObjectTpe :: Nil
else removeLaterObjects(parents map this),
decls, clazz)
case _ =>
@@ -157,7 +157,7 @@ trait Erasure {
}
def applyInArray(tp: Type): Type = tp match {
- case TypeRef(pre, sym, args) if (sym.isDerivedValueClass) => eraseNormalClassRef(pre, sym)
+ case tref @ TypeRef(_, sym, _) if sym.isDerivedValueClass => eraseNormalClassRef(tref)
case _ => apply(tp)
}
}
@@ -214,9 +214,6 @@ trait Erasure {
specialConstructorErasure(clazz, restpe)
case ExistentialType(tparams, restpe) =>
specialConstructorErasure(clazz, restpe)
- case RefinedType(parents, decls) =>
- specialConstructorErasure(
- clazz, specialScalaErasure.mergeParents(parents))
case mt @ MethodType(params, restpe) =>
MethodType(
cloneSymbolsAndModify(params, specialScalaErasure),
@@ -225,15 +222,7 @@ trait Erasure {
typeRef(pre, clazz, List())
case tp =>
if (!(clazz == ArrayClass || tp.isError))
- // See SI-6556. It seems in some cases the result constructor
- // type of an anonymous class is a different version of the class.
- // This has nothing to do with value classes per se.
- // We simply used a less discriminating transform before, that
- // did not look at the cases in detail.
- // It seems there is a deeper problem here, which needs
- // following up to. But we will not risk regressions
- // in 2.10 because of it.
- log(s"!!! unexpected constructor erasure $tp for $clazz")
+ assert(clazz == ArrayClass || tp.isError, s"!!! unexpected constructor erasure $tp for $clazz")
specialScalaErasure(tp)
}
}
@@ -263,7 +252,7 @@ trait Erasure {
* An intersection such as `Object with Trait` erases to Object.
*/
def mergeParents(parents: List[Type]): Type =
- if (parents.isEmpty) ObjectClass.tpe
+ if (parents.isEmpty) ObjectTpe
else parents.head
}
@@ -271,11 +260,11 @@ trait Erasure {
/** 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.
+ * are then later unwrapped to the underlying parameter type in phase posterasure.
*/
object specialScalaErasure extends ScalaErasureMap {
override def eraseDerivedValueClassRef(tref: TypeRef): Type =
- ErasedValueType(tref)
+ ErasedValueType(tref.sym, erasedValueClassArg(tref))
}
object javaErasure extends JavaErasureMap
@@ -291,11 +280,11 @@ trait Erasure {
}
object boxingErasure extends ScalaErasureMap {
- override def eraseNormalClassRef(pre: Type, clazz: Symbol) =
- if (isPrimitiveValueClass(clazz)) boxedClass(clazz).tpe
- else super.eraseNormalClassRef(pre, clazz)
+ override def eraseNormalClassRef(tref: TypeRef) =
+ if (isPrimitiveValueClass(tref.sym)) boxedClass(tref.sym).tpe
+ else super.eraseNormalClassRef(tref)
override def eraseDerivedValueClassRef(tref: TypeRef) =
- super.eraseNormalClassRef(tref.pre, tref.sym)
+ super.eraseNormalClassRef(tref)
}
/** The intersection dominator (SLS 3.7) of a list of types is computed as follows.
@@ -311,7 +300,7 @@ trait Erasure {
* - Otherwise, the dominator is the first element of the span.
*/
def intersectionDominator(parents: List[Type]): Type = {
- if (parents.isEmpty) ObjectClass.tpe
+ if (parents.isEmpty) ObjectTpe
else {
val psyms = parents map (_.typeSymbol)
if (psyms contains ArrayClass) {
@@ -333,10 +322,6 @@ trait Erasure {
}
}
- /** 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
@@ -364,8 +349,7 @@ trait Erasure {
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))
+ MethodType(List(index.cloneSymbol.setInfo(specialErasure(sym)(index.tpe)), tvar), UnitTpe)
}
else specialErasure(sym)(tp)
} else if (
diff --git a/src/reflect/scala/reflect/internal/transform/PostErasure.scala b/src/reflect/scala/reflect/internal/transform/PostErasure.scala
new file mode 100644
index 0000000000..f0c7d0f050
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/transform/PostErasure.scala
@@ -0,0 +1,19 @@
+package scala.reflect
+package internal
+package transform
+
+trait PostErasure {
+ val global: SymbolTable
+ import global._
+ import definitions._
+
+ object elimErasedValueType extends TypeMap {
+ def apply(tp: Type) = tp match {
+ case ConstantType(Constant(tp: Type)) => ConstantType(Constant(apply(tp)))
+ case ErasedValueType(_, underlying) => underlying
+ case _ => mapOver(tp)
+ }
+ }
+
+ def transformInfo(sym: Symbol, tp: Type) = elimErasedValueType(tp)
+}
diff --git a/src/reflect/scala/reflect/internal/transform/RefChecks.scala b/src/reflect/scala/reflect/internal/transform/RefChecks.scala
index d6108ab665..4ca114e781 100644
--- a/src/reflect/scala/reflect/internal/transform/RefChecks.scala
+++ b/src/reflect/scala/reflect/internal/transform/RefChecks.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package internal
package transform
@@ -10,4 +11,4 @@ trait RefChecks {
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
index 71cc80895d..296ccde443 100644
--- a/src/reflect/scala/reflect/internal/transform/Transforms.scala
+++ b/src/reflect/scala/reflect/internal/transform/Transforms.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package internal
package transform
@@ -25,17 +26,20 @@ trait Transforms { self: SymbolTable =>
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)
+ private val postErasureLazy = new Lazy(new { val global: Transforms.this.type = self } with PostErasure)
def refChecks = refChecksLazy.force
def uncurry = uncurryLazy.force
def erasure = erasureLazy.force
+ def postErasure = postErasureLazy.force
def transformedType(sym: Symbol) =
- erasure.transformInfo(sym,
- uncurry.transformInfo(sym,
- refChecks.transformInfo(sym, sym.info)))
+ postErasure.transformInfo(sym,
+ erasure.transformInfo(sym,
+ uncurry.transformInfo(sym,
+ refChecks.transformInfo(sym, sym.info))))
def transformedType(tpe: Type) =
- erasure.scalaErasure(uncurry.uncurry(tpe))
+ postErasure.elimErasedValueType(erasure.scalaErasure(uncurry.uncurry(tpe)))
}
diff --git a/src/reflect/scala/reflect/internal/transform/UnCurry.scala b/src/reflect/scala/reflect/internal/transform/UnCurry.scala
index 00c7c3de9a..abea8bed9f 100644
--- a/src/reflect/scala/reflect/internal/transform/UnCurry.scala
+++ b/src/reflect/scala/reflect/internal/transform/UnCurry.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package internal
package transform
@@ -10,6 +11,14 @@ trait UnCurry {
import global._
import definitions._
+ /** Note: changing tp.normalize to tp.dealias in this method leads to a single
+ * test failure: run/t5688.scala, where instead of the expected output
+ * Vector(ta, tb, tab)
+ * we instead get
+ * Vector(tab, tb, tab)
+ * I think that difference is not the product of sentience but of randomness.
+ * Let us figure out why it is and then change this method.
+ */
private def expandAlias(tp: Type): Type = if (!tp.isHigherKinded) tp.normalize else tp
val uncurry: TypeMap = new TypeMap {
@@ -37,7 +46,7 @@ trait UnCurry {
apply(seqType(arg))
case TypeRef(pre, JavaRepeatedParamClass, arg :: Nil) =>
apply(arrayType(
- if (isUnboundedGeneric(arg)) ObjectClass.tpe else arg))
+ if (isUnboundedGeneric(arg)) ObjectTpe else arg))
case _ =>
expandAlias(mapOver(tp))
}
diff --git a/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala b/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala
new file mode 100644
index 0000000000..10a8b4c812
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala
@@ -0,0 +1,122 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ */
+
+package scala
+package reflect.internal.util
+
+import scala.reflect.io.AbstractFile
+import java.security.cert.Certificate
+import java.security.{ ProtectionDomain, CodeSource }
+import java.net.{ URL, URLConnection, URLStreamHandler }
+import scala.collection.{ mutable, immutable }
+
+/**
+ * A class loader that loads files from a {@link scala.tools.nsc.io.AbstractFile}.
+ *
+ * @author Lex Spoon
+ */
+class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader)
+ extends ClassLoader(parent)
+ with ScalaClassLoader
+{
+ protected def classNameToPath(name: String): String =
+ if (name endsWith ".class") name
+ else name.replace('.', '/') + ".class"
+
+ protected def findAbstractFile(name: String): AbstractFile = {
+ var file: AbstractFile = root
+ val pathParts = name split '/'
+
+ for (dirPart <- pathParts.init) {
+ file = file.lookupName(dirPart, directory = true)
+ if (file == null)
+ return null
+ }
+
+ file.lookupName(pathParts.last, directory = false) match {
+ case null => null
+ case file => file
+ }
+ }
+
+ protected def dirNameToPath(name: String): String =
+ name.replace('.', '/')
+
+ protected def findAbstractDir(name: String): AbstractFile = {
+ var file: AbstractFile = root
+ val pathParts = dirNameToPath(name) split '/'
+
+ for (dirPart <- pathParts) {
+ file = file.lookupName(dirPart, directory = true)
+ if (file == null)
+ return null
+ }
+
+ file
+ }
+
+ // parent delegation in JCL uses getResource; so either add parent.getResAsStream
+ // or implement findResource, which we do here as a study in scarlet (my complexion
+ // after looking at CLs and URLs)
+ override def findResource(name: String): URL = findAbstractFile(name) match {
+ case null => null
+ case file => new URL(null, "repldir:" + file.path, new URLStreamHandler {
+ override def openConnection(url: URL): URLConnection = new URLConnection(url) {
+ override def connect() { }
+ override def getInputStream = file.input
+ }
+ })
+ }
+
+ // this inverts delegation order: super.getResAsStr calls parent.getRes if we fail
+ override def getResourceAsStream(name: String) = findAbstractFile(name) match {
+ case null => super.getResourceAsStream(name)
+ case file => file.input
+ }
+ // ScalaClassLoader.classBytes uses getResAsStream, so we'll try again before delegating
+ override def classBytes(name: String): Array[Byte] = findAbstractFile(classNameToPath(name)) match {
+ case null => super.classBytes(name)
+ case file => file.toByteArray
+ }
+ override def findClass(name: String): Class[_] = {
+ val bytes = classBytes(name)
+ if (bytes.length == 0)
+ throw new ClassNotFoundException(name)
+ else
+ defineClass(name, bytes, 0, bytes.length, protectionDomain)
+ }
+
+ lazy val protectionDomain = {
+ val cl = Thread.currentThread().getContextClassLoader()
+ val resource = cl.getResource("scala/runtime/package.class")
+ if (resource == null || resource.getProtocol != "jar") null else {
+ val s = resource.getPath
+ val n = s.lastIndexOf('!')
+ if (n < 0) null else {
+ val path = s.substring(0, n)
+ new ProtectionDomain(new CodeSource(new URL(path), null.asInstanceOf[Array[Certificate]]), null, this, null)
+ }
+ }
+ }
+
+ private val packages = mutable.Map[String, Package]()
+
+ override def definePackage(name: String, specTitle: String, specVersion: String, specVendor: String, implTitle: String, implVersion: String, implVendor: String, sealBase: URL): Package = {
+ throw new UnsupportedOperationException()
+ }
+
+ override def getPackage(name: String): Package = {
+ findAbstractDir(name) match {
+ case null => super.getPackage(name)
+ case file => packages.getOrElseUpdate(name, {
+ val ctor = classOf[Package].getDeclaredConstructor(classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[URL], classOf[ClassLoader])
+ ctor.setAccessible(true)
+ ctor.newInstance(name, null, null, null, null, null, null, null, this)
+ })
+ }
+ }
+
+ override def getPackages(): Array[Package] =
+ root.iterator.filter(_.isDirectory).map(dir => getPackage(dir.name)).toArray
+}
diff --git a/src/reflect/scala/reflect/internal/util/Collections.scala b/src/reflect/scala/reflect/internal/util/Collections.scala
index 2ba15e0776..d128521be8 100644
--- a/src/reflect/scala/reflect/internal/util/Collections.scala
+++ b/src/reflect/scala/reflect/internal/util/Collections.scala
@@ -3,7 +3,8 @@
* @author Paul Phillips
*/
-package scala.reflect.internal.util
+package scala
+package reflect.internal.util
import scala.collection.{ mutable, immutable }
import scala.annotation.tailrec
@@ -33,15 +34,42 @@ trait Collections {
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
+
+ /** These are all written in terms of List because we're trying to wring all
+ * the performance we can and List is used almost exclusively in the compiler,
+ * but people are branching out in their collections so here's an overload.
+ */
+ final def mforeach[A](xss: List[List[A]])(f: A => Unit) = xss foreach (_ foreach f)
+ final def mforeach[A](xss: Traversable[Traversable[A]])(f: A => Unit) = xss foreach (_ foreach f)
+
+ /** A version of List#map, specialized for List, and optimized to avoid allocation if `as` is empty */
+ final def mapList[A, B](as: List[A])(f: A => B): List[B] = if (as eq Nil) Nil else {
+ val head = new ::[B](f(as.head), Nil)
+ var tail: ::[B] = head
+ var rest = as.tail
+ while (rest ne Nil) {
+ val next = new ::(f(rest.head), Nil)
+ tail.tl = next
+ tail = next
+ rest = rest.tail
+ }
+ head
+ }
+
+ final def collectFirst[A, B](as: List[A])(pf: PartialFunction[A, B]): Option[B] = {
+ @tailrec
+ def loop(rest: List[A]): Option[B] = rest match {
+ case Nil => None
+ case a :: as if pf.isDefinedAt(a) => Some(pf(a))
+ case a :: as => loop(as)
+ }
+ loop(as)
+ }
final def map2[A, B, C](xs1: List[A], xs2: List[B])(f: (A, B) => C): List[C] = {
val lb = new ListBuffer[C]
@@ -54,20 +82,60 @@ trait Collections {
}
lb.toList
}
+
+ /** like map2, but returns list `xs` itself - instead of a copy - if function
+ * `f` maps all elements to themselves.
+ */
+ final def map2Conserve[A <: AnyRef, B](xs: List[A], ys: List[B])(f: (A, B) => A): List[A] = {
+ // Note to developers: there exists a duplication between this function and `List#mapConserve`.
+ // If any successful optimization attempts or other changes are made, please rehash them there too.
+ @tailrec
+ def loop(mapped: ListBuffer[A], unchanged: List[A], pending0: List[A], pending1: List[B]): List[A] = {
+ if (pending0.isEmpty || pending1.isEmpty) {
+ if (mapped eq null) unchanged
+ else mapped.prependToList(unchanged)
+ } else {
+ val head00 = pending0.head
+ val head01 = pending1.head
+ val head1 = f(head00, head01)
+
+ if ((head1 eq head00.asInstanceOf[AnyRef])) {
+ loop(mapped, unchanged, pending0.tail, pending1.tail)
+ } else {
+ val b = if (mapped eq null) new ListBuffer[A] else mapped
+ var xc = unchanged
+ while ((xc ne pending0) && (xc ne pending1)) {
+ b += xc.head
+ xc = xc.tail
+ }
+ b += head1
+ val tail0 = pending0.tail
+ val tail1 = pending1.tail
+ loop(b, tail0, tail0, tail1)
+ }
+ }
+ }
+ loop(null, xs, xs, ys)
+ }
+
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 lb: ListBuffer[C] = null
var ys1 = xs1
var ys2 = xs2
while (!ys1.isEmpty && !ys2.isEmpty) {
- lb ++= f(ys1.head, ys2.head)
+ val cs = f(ys1.head, ys2.head)
+ if (cs ne Nil) {
+ if (lb eq null) lb = new ListBuffer[C]
+ lb ++= cs
+ }
ys1 = ys1.tail
ys2 = ys2.tail
}
- lb.toList
+ if (lb eq null) Nil else lb.result
}
final def flatCollect[A, B](elems: List[A])(pf: PartialFunction[A, Traversable[B]]): List[B] = {
@@ -141,7 +209,7 @@ trait Collections {
ys1 = ys1.tail
ys2 = ys2.tail
}
- buf.result
+ buf.result()
}
final def foreach2[A, B](xs1: List[A], xs2: List[B])(f: (A, B) => Unit): Unit = {
var ys1 = xs1
@@ -189,18 +257,6 @@ trait Collections {
}
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
@@ -216,6 +272,11 @@ trait Collections {
true
}
+ final def sequence[A](as: List[Option[A]]): Option[List[A]] = {
+ if (as.exists (_.isEmpty)) None
+ else Some(as.flatten)
+ }
+
final def transposeSafe[A](ass: List[List[A]]): Option[List[List[A]]] = try {
Some(ass.transpose)
} catch {
@@ -223,5 +284,4 @@ trait Collections {
}
}
-object Collections extends Collections { }
-
+object Collections extends Collections
diff --git a/src/reflect/scala/reflect/internal/util/FreshNameCreator.scala b/src/reflect/scala/reflect/internal/util/FreshNameCreator.scala
new file mode 100644
index 0000000000..8442c1015f
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/FreshNameCreator.scala
@@ -0,0 +1,28 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect.internal
+package util
+
+import java.util.concurrent.ConcurrentHashMap
+import java.util.concurrent.atomic.AtomicLong
+import scala.collection.mutable
+import scala.reflect.NameTransformer
+
+class FreshNameCreator(creatorPrefix: String = "") {
+ protected val counters = new ConcurrentHashMap[String, AtomicLong]()
+
+ /**
+ * Create a fresh name with the given prefix. It is guaranteed
+ * that the returned name has never been returned by a previous
+ * call to this function (provided the prefix does not end in a digit).
+ */
+ def newName(prefix: String): String = {
+ val safePrefix = NameTransformer.encode(prefix)
+ counters.putIfAbsent(safePrefix, new AtomicLong(0))
+ val idx = counters.get(safePrefix).incrementAndGet()
+ s"$creatorPrefix$safePrefix$idx"
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/util/HashSet.scala b/src/reflect/scala/reflect/internal/util/HashSet.scala
index 4135f3c469..b4178e055d 100644
--- a/src/reflect/scala/reflect/internal/util/HashSet.scala
+++ b/src/reflect/scala/reflect/internal/util/HashSet.scala
@@ -3,11 +3,11 @@
* @author Martin Odersky
*/
-package scala.reflect.internal.util
+package scala
+package reflect
+package 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)
diff --git a/src/reflect/scala/reflect/internal/util/Origins.scala b/src/reflect/scala/reflect/internal/util/Origins.scala
index 3259a12163..2eb4fa29d5 100644
--- a/src/reflect/scala/reflect/internal/util/Origins.scala
+++ b/src/reflect/scala/reflect/internal/util/Origins.scala
@@ -3,12 +3,11 @@
* @author Paul Phillips
*/
-package scala.reflect
+package scala
+package 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.
diff --git a/src/reflect/scala/reflect/internal/util/Position.scala b/src/reflect/scala/reflect/internal/util/Position.scala
index 8f287a1640..0192d31806 100644
--- a/src/reflect/scala/reflect/internal/util/Position.scala
+++ b/src/reflect/scala/reflect/internal/util/Position.scala
@@ -1,248 +1,210 @@
/* NSC -- new Scala compiler
* Copyright 2005-2013 LAMP/EPFL
* @author Martin Odersky
- *
*/
-package scala.reflect.internal.util
+package scala
+package reflect
+package internal
+package util
-import scala.reflect.ClassTag
-import scala.reflect.internal.FatalError
-import scala.reflect.macros.Attachments
+/** @inheritdoc */
+class Position extends scala.reflect.api.Position with InternalPositionImpl with DeprecatedPosition {
+ type Pos = Position
+ def pos: Position = this
+ def withPos(newPos: Position): macros.Attachments { type Pos = Position.this.Pos } = newPos
+
+ protected def fail(what: String) = throw new UnsupportedOperationException(s"Position.$what on $this")
+
+ // If scala-refactoring extends Position directly it seems I have no
+ // choice but to offer all the concrete methods.
+ def isDefined = false
+ def isRange = false
+ def source: SourceFile = NoSourceFile
+ def start: Int = fail("start")
+ def point: Int = fail("point")
+ def end: Int = fail("end")
+}
object Position {
val tabInc = 8
+ private def validate[T <: Position](pos: T): T = {
+ if (pos.isRange)
+ assert(pos.start <= pos.end, s"bad position: ${pos.show}")
+
+ pos
+ }
+
/** 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"
+ val pos = if (posIn eq null) NoPosition else posIn
+ val prefix = pos.source match {
+ case NoSourceFile => ""
+ case s if shortenFile => s.file.name + ":"
+ case s => s.file.path + ":"
}
+ prefix + (pos showError msg)
}
-}
-
-/** 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.
- */
-abstract class Position extends scala.reflect.api.Position { self =>
-
- type Pos = Position
-
- def pos: Position = this
-
- def withPos(newPos: Position): Attachments { type Pos = self.Pos } = newPos
-
- /** An optional value containing the source file referred to by this position, or
- * None if not defined.
- */
- def source: SourceFile = throw new UnsupportedOperationException(s"Position.source on ${this.getClass}")
-
- /** 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(s"Position.start on ${this.getClass}")
-
- /** 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(s"Position.point on ${this.getClass}")
-
- /** 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(s"Position.end on ${this.getClass}")
-
- /** 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
+ def offset(source: SourceFile, point: Int): Position = validate(new OffsetPosition(source, point))
+ def range(source: SourceFile, start: Int, point: Int, end: Int): Position = validate(new RangePosition(source, start, point, end))
+ def transparent(source: SourceFile, start: Int, point: Int, end: Int): Position = validate(new TransparentPosition(source, start, point, end))
+}
- /** If this is a range position, the offset position of its start.
- * Otherwise the position itself
- */
- def focusStart: Position = this
+class OffsetPosition(sourceIn: SourceFile, pointIn: Int) extends DefinedPosition {
+ override def isRange = false
+ override def source = sourceIn
+ override def point = pointIn
+ override def start = point
+ override def end = point
+}
+class RangePosition(sourceIn: SourceFile, startIn: Int, pointIn: Int, endIn: Int) extends OffsetPosition(sourceIn, pointIn) {
+ override def isRange = true
+ override def start = startIn
+ override def end = endIn
+}
+class TransparentPosition(sourceIn: SourceFile, startIn: Int, pointIn: Int, endIn: Int) extends RangePosition(sourceIn, startIn, pointIn, endIn) {
+ override def isTransparent = true
+}
+case object NoPosition extends UndefinedPosition
+case class FakePos(msg: String) extends UndefinedPosition {
+ override def toString = msg
+}
- /** If this is a range position, the offset position of its point.
- * Otherwise the position itself
- */
- def focus: Position = this
+sealed abstract class DefinedPosition extends Position {
+ final override def isDefined = true
+ override def equals(that: Any) = that match {
+ case that: DefinedPosition => source.file == that.source.file && start == that.start && point == that.point && end == that.end
+ case _ => false
+ }
+ override def hashCode = Seq[Any](source.file, start, point, end).##
+ override def toString = (
+ if (isRange) s"RangePosition($canonicalPath, $start, $point, $end)"
+ else s"source-$canonicalPath,line-$line,$pointMessage$point"
+ )
+ private def pointMessage = if (point > source.length) "out-of-bounds-" else "offset="
+ private def canonicalPath = source.file.canonicalPath
+}
- /** If this is a range position, the offset position of its end.
- * Otherwise the position itself
- */
- def focusEnd: Position = this
+sealed abstract class UndefinedPosition extends Position {
+ final override def isDefined = false
+ override def isRange = false
+ override def source = NoSourceFile
+ override def start = fail("start")
+ override def point = fail("point")
+ override def end = fail("end")
+}
- /** 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
+private[util] trait InternalPositionImpl {
+ self: Position =>
- /** 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)
+ // The methods which would be abstract in Position if it were
+ // possible to change Position.
+ def isDefined: Boolean
+ def isRange: Boolean
+ def source: SourceFile
+ def start: Int
+ def point: Int
+ def end: Int
- /** 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.
+ /** Map this position to its position in the original source file
+ * (which may be this position unchanged.)
*/
- def precedes(pos: Position): Boolean =
- isDefined && pos.isDefined && endOrPoint <= pos.startOrPoint
+ def finalPosition: Pos = source positionInUltimateSource this
- /** 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
+ def isTransparent = false
+ def isOffset = isDefined && !isRange
+ def isOpaqueRange = isRange && !isTransparent
+ def pointOrElse(alt: Int): Int = if (isDefined) point else alt
+ def makeTransparent: Position = if (isOpaqueRange) Position.transparent(source, start, point, end) else this
- /** 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.
+ /** Copy a range position with a changed value.
*/
- def overlaps(pos: Position): Boolean =
- isRange && pos.isRange &&
- ((pos.start < end && start < pos.end) || (start < pos.end && pos.start < end))
+ def withStart(start: Int): Position = copyRange(start = start)
+ def withPoint(point: Int): Position = if (isRange) copyRange(point = point) else Position.offset(source, point)
+ def withEnd(end: Int): Position = copyRange(end = end)
+ def withSource(source: SourceFile): Position = copyRange(source = source)
+ def withShift(shift: Int): Position = Position.range(source, start + shift, point + shift, end + shift)
- /** Does this position cover the same range as that position?
- * Holds only if both position are ranges
+ /** Convert a range position to a simple offset.
*/
- 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 focusStart: Position = if (this.isRange) asOffset(start) else this
+ def focus: Position = if (this.isRange) asOffset(point) else this
+ def focusEnd: Position = if (this.isRange) asOffset(end) else this
+
+ /** If you have it in for punctuation you might not like these methods.
+ * However I think they're aptly named.
+ *
+ * | means union
+ * ^ means "the point" (look, it's a caret)
+ * |^ means union, taking the point of the rhs
+ * ^| means union, taking the point of the lhs
*/
- 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 = {
+ def |(that: Position, poses: Position*): Position = poses.foldLeft(this | that)(_ | _)
+ def |(that: Position): Position = this union that
+ def ^(point: Int): Position = this withPoint point
+ def |^(that: Position): Position = (this | that) ^ that.point
+ def ^|(that: Position): Position = (this | that) ^ this.point
+
+ def union(pos: Position): Position = (
+ if (!pos.isRange) this
+ else if (this.isRange) copyRange(start = start min pos.start, end = end max pos.end)
+ else pos
+ )
+
+ def includes(pos: Position): Boolean = isRange && pos.isDefined && start <= pos.start && pos.end <= end
+ def properlyIncludes(pos: Position): Boolean = includes(pos) && (start < pos.start || pos.end < end)
+ def precedes(pos: Position): Boolean = bothDefined(pos) && end <= pos.start
+ def properlyPrecedes(pos: Position): Boolean = bothDefined(pos) && end < pos.start
+ def sameRange(pos: Position): Boolean = bothRanges(pos) && start == pos.start && end == pos.end
+ // This works because it's a range position invariant that S1 < E1 and S2 < E2.
+ // So if S1 < E2 and S2 < E1, then both starts precede both ends, which is the
+ // necessary condition to establish that there is overlap.
+ def overlaps(pos: Position): Boolean = bothRanges(pos) && start < pos.end && pos.start < end
+
+ def line: Int = if (hasSource) source.offsetToLine(point) + 1 else 0
+ def column: Int = if (hasSource) calculateColumn() else 0
+ def lineContent: String = if (hasSource) source.lineToString(line - 1) else ""
+ def lineCaret: String = if (hasSource) " " * (column - 1) + "^" else ""
+ @deprecated("use `lineCaret`", since="2.11.0")
+ def lineCarat: String = lineCaret
+
+ def showError(msg: String): String = {
+ def escaped(s: String) = {
+ def u(c: Int) = f"\\u$c%04x"
+ def uable(c: Int) = (c < 0x20 && c != '\t') || c == 0x7F
+ if (s exists (c => uable(c))) {
+ val sb = new StringBuilder
+ s foreach (c => sb append (if (uable(c)) u(c) else c))
+ sb.toString
+ } else s
+ }
+ def errorAt(p: Pos) = {
+ def where = p.line
+ def content = escaped(p.lineContent)
+ def indicator = p.lineCaret
+ f"$where: $msg%n$content%n$indicator"
+ }
+ finalPosition match {
+ case FakePos(fmsg) => s"$fmsg $msg"
+ case NoPosition => msg
+ case pos => errorAt(pos)
+ }
+ }
+ def showDebug: String = toString
+ def show = (
+ if (isOpaqueRange) s"[$start:$end]"
+ else if (isTransparent) s"<$start:$end>"
+ else if (isDefined) s"[$point]"
+ else "[NoPosition]"
+ )
+
+ private def asOffset(point: Int): Position = Position.offset(source, point)
+ private def copyRange(source: SourceFile = source, start: Int = start, point: Int = point, end: Int = end): Position =
+ Position.range(source, start, point, end)
+
+ private def calculateColumn(): Int = {
var idx = source.lineToOffset(source.offsetToLine(point))
var col = 0
while (idx != point) {
@@ -251,61 +213,39 @@ class OffsetPosition(override val source: SourceFile, override val point: Int) e
}
col + 1
}
+ private def hasSource = source ne NoSourceFile
+ private def bothRanges(that: Position) = isRange && that.isRange
+ private def bothDefined(that: Position) = isDefined && that.isDefined
+}
- override def union(pos: Position) = if (pos.isRange) pos else this
+/** Holding cell for methods unused and/or unnecessary. */
+private[util] trait DeprecatedPosition {
+ self: Position =>
- 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
+ @deprecated("use `point`", "2.9.0") // Used in SBT 0.12.4
+ def offset: Option[Int] = if (isDefined) Some(point) else None
- 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+"]"
-}
+ @deprecated("use `focus`", "2.11.0")
+ def toSingleLine: Position = this
-/** 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) sys.error("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
- }
+ @deprecated("use `line`", "2.11.0")
+ def safeLine: Int = line
- override def toString = "RangePosition("+source.file.canonicalPath+", "+start+", "+point+", "+end+")"
- override def show = "["+start+":"+end+"]"
- private var focusCache: Position = NoPosition
-}
+ @deprecated("use `showDebug`", "2.11.0")
+ def dbgString: String = showDebug
-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+">"
+ @deprecated("use `finalPosition`", "2.11.0")
+ def inUltimateSource(source: SourceFile): Position = source positionInUltimateSource this
+
+ @deprecated("use `lineCaret`", since="2.11.0")
+ def lineWithCarat(maxWidth: Int): (String, String) = ("", "")
+
+ @deprecated("Use `withSource(source)` and `withShift`", "2.11.0")
+ def withSource(source: SourceFile, shift: Int): Position = this withSource source withShift shift
+
+ @deprecated("Use `start` instead", "2.11.0")
+ def startOrPoint: Int = if (isRange) start else point
+
+ @deprecated("Use `end` instead", "2.11.0")
+ def endOrPoint: Int = if (isRange) end else point
}
diff --git a/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala b/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala
new file mode 100644
index 0000000000..63ea6e2c49
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala
@@ -0,0 +1,124 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala
+package reflect.internal.util
+
+import java.lang.{ ClassLoader => JClassLoader }
+import java.lang.reflect.{ Constructor, Modifier, Method }
+import java.io.{ File => JFile }
+import java.net.{ URLClassLoader => JURLClassLoader }
+import java.net.URL
+import scala.reflect.runtime.ReflectionUtils.unwrapHandler
+import ScalaClassLoader._
+import scala.util.control.Exception.{ catching }
+import scala.language.implicitConversions
+import scala.reflect.{ ClassTag, classTag }
+
+trait HasClassPath {
+ def classPathURLs: Seq[URL]
+}
+
+/** A wrapper around java.lang.ClassLoader to lower the annoyance
+ * of java reflection.
+ */
+trait ScalaClassLoader extends JClassLoader {
+ /** Executing an action with this classloader as context classloader */
+ def asContext[T](action: => T): T = {
+ val saved = contextLoader
+ try { setContext(this) ; action }
+ finally setContext(saved)
+ }
+ def setAsContext() { setContext(this) }
+
+ /** Load and link a class with this classloader */
+ def tryToLoadClass[T <: AnyRef](path: String): Option[Class[T]] = tryClass(path, initialize = false)
+ /** Load, link and initialize a class with this classloader */
+ def tryToInitializeClass[T <: AnyRef](path: String): Option[Class[T]] = tryClass(path, initialize = true)
+
+ private def tryClass[T <: AnyRef](path: String, initialize: Boolean): Option[Class[T]] =
+ catching(classOf[ClassNotFoundException], classOf[SecurityException]) opt
+ Class.forName(path, initialize, this).asInstanceOf[Class[T]]
+
+ /** Create an instance of a class with this classloader */
+ def create(path: String): AnyRef =
+ tryToInitializeClass[AnyRef](path).map(_.newInstance()).orNull
+
+ /** The actual bytes for a class file, or an empty array if it can't be found. */
+ def classBytes(className: String): Array[Byte] = classAsStream(className) match {
+ case null => Array()
+ case stream => scala.reflect.io.Streamable.bytes(stream)
+ }
+
+ /** An InputStream representing the given class name, or null if not found. */
+ def classAsStream(className: String) =
+ getResourceAsStream(className.replaceAll("""\.""", "/") + ".class")
+
+ /** Run the main method of a class to be loaded by this classloader */
+ def run(objectName: String, arguments: Seq[String]) {
+ val clsToRun = tryToInitializeClass(objectName) getOrElse (
+ throw new ClassNotFoundException(objectName)
+ )
+ val method = clsToRun.getMethod("main", classOf[Array[String]])
+ if (!Modifier.isStatic(method.getModifiers))
+ throw new NoSuchMethodException(objectName + ".main is not static")
+
+ try asContext(method.invoke(null, Array(arguments.toArray: AnyRef): _*)) // !!! : AnyRef shouldn't be necessary
+ catch unwrapHandler({ case ex => throw ex })
+ }
+}
+
+/** Methods for obtaining various classloaders.
+ * appLoader: the application classloader. (Also called the java system classloader.)
+ * extLoader: the extension classloader.
+ * bootLoader: the boot classloader.
+ * contextLoader: the context classloader.
+ */
+object ScalaClassLoader {
+ /** Returns loaders which are already ScalaClassLoaders unaltered,
+ * and translates java.net.URLClassLoaders into scala URLClassLoaders.
+ * Otherwise creates a new wrapper.
+ */
+ implicit def apply(cl: JClassLoader): ScalaClassLoader = cl match {
+ case cl: ScalaClassLoader => cl
+ case cl: JURLClassLoader => new URLClassLoader(cl.getURLs.toSeq, cl.getParent)
+ case _ => new JClassLoader(cl) with ScalaClassLoader
+ }
+ def contextLoader = apply(Thread.currentThread.getContextClassLoader)
+ def appLoader = apply(JClassLoader.getSystemClassLoader)
+ def setContext(cl: JClassLoader) =
+ Thread.currentThread.setContextClassLoader(cl)
+ def savingContextLoader[T](body: => T): T = {
+ val saved = contextLoader
+ try body
+ finally setContext(saved)
+ }
+
+ class URLClassLoader(urls: Seq[URL], parent: JClassLoader)
+ extends JURLClassLoader(urls.toArray, parent)
+ with ScalaClassLoader
+ with HasClassPath {
+
+ private var classloaderURLs: Seq[URL] = urls
+ def classPathURLs: Seq[URL] = classloaderURLs
+
+ /** Override to widen to public */
+ override def addURL(url: URL) = {
+ classloaderURLs :+= url
+ super.addURL(url)
+ }
+ }
+
+ def fromURLs(urls: Seq[URL], parent: ClassLoader = null): URLClassLoader =
+ new URLClassLoader(urls, parent)
+
+ /** True if supplied class exists in supplied path */
+ def classExists(urls: Seq[URL], name: String): Boolean =
+ (fromURLs(urls) tryToLoadClass name).isDefined
+
+ /** Finding what jar a clazz or instance came from */
+ def originOfClass(x: Class[_]): Option[URL] =
+ Option(x.getProtectionDomain.getCodeSource) flatMap (x => Option(x.getLocation))
+}
diff --git a/src/reflect/scala/reflect/internal/util/Set.scala b/src/reflect/scala/reflect/internal/util/Set.scala
index 36bdb8174a..635bfb05e4 100644
--- a/src/reflect/scala/reflect/internal/util/Set.scala
+++ b/src/reflect/scala/reflect/internal/util/Set.scala
@@ -2,7 +2,8 @@
* Copyright 2005-2013 LAMP/EPFL
* @author Martin Odersky
*/
-package scala.reflect.internal.util
+package scala
+package reflect.internal.util
/** A common class for lightweight sets.
*/
@@ -18,11 +19,8 @@ abstract class Set[T <: AnyRef] {
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
index bc2d0ee4db..a2642628a4 100644
--- a/src/reflect/scala/reflect/internal/util/SourceFile.scala
+++ b/src/reflect/scala/reflect/internal/util/SourceFile.scala
@@ -4,7 +4,8 @@
*/
-package scala.reflect.internal.util
+package scala
+package reflect.internal.util
import scala.reflect.io.{ AbstractFile, VirtualFile }
import scala.collection.mutable.ArrayBuffer
@@ -15,16 +16,16 @@ 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 content: Array[Char] // normalized, must end in SU
+ def file : AbstractFile
+ def isLineBreak(idx: Int): Boolean
+ def isEndOfLine(idx: Int): Boolean
def isSelfContained: Boolean
def length : Int
- def position(offset: Int) : Position = {
+ def position(offset: Int): Position = {
assert(offset < length, file + ": " + offset + " >= " + length)
- new OffsetPosition(this, offset)
+ Position.offset(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
@@ -34,14 +35,14 @@ abstract class SourceFile {
*/
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 ""
+ def lineToString(index: Int): String = {
+ val start = lineToOffset(index)
+ var end = start
+ while (end < length && !isEndOfLine(end)) end += 1
+ new String(content, start, end - start)
+ }
@tailrec
final def skipWhitespace(offset: Int): Int =
@@ -56,6 +57,7 @@ object NoSourceFile extends SourceFile {
def content = Array()
def file = NoFile
def isLineBreak(idx: Int) = false
+ def isEndOfLine(idx: Int) = false
def isSelfContained = true
def length = -1
def offsetToLine(offset: Int) = -1
@@ -81,7 +83,6 @@ object ScriptSourceFile {
}
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)
@@ -90,19 +91,23 @@ object ScriptSourceFile {
stripped
}
+
+ def apply(underlying: BatchSourceFile) = {
+ val headerLen = headerLength(underlying.content)
+ new ScriptSourceFile(underlying, underlying.content drop headerLen, headerLen)
+ }
}
-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 pos.withSource(underlying, start)
+ else pos withSource underlying withShift start
}
/** a file whose contents do not change over time */
-class BatchSourceFile(val file : AbstractFile, val content0: Array[Char]) extends SourceFile {
+class BatchSourceFile(val file : AbstractFile, content0: 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)
@@ -129,18 +134,30 @@ class BatchSourceFile(val file : AbstractFile, val content0: Array[Char]) extend
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)
- }
+ private def charAtIsEOL(idx: Int)(p: Char => Boolean) = {
+ // don't identify the CR in CR LF as a line break, since LF will do.
+ def notCRLF0 = content(idx) != CR || !content.isDefinedAt(idx + 1) || content(idx + 1) != LF
+
+ idx < length && notCRLF0 && p(content(idx))
+ }
+
+ def isLineBreak(idx: Int) = charAtIsEOL(idx)(isLineBreakChar)
+
+ /** True if the index is included by an EOL sequence. */
+ def isEndOfLine(idx: Int) = (content isDefinedAt idx) && PartialFunction.cond(content(idx)) {
+ case CR | LF => true
+ }
+
+ /** True if the index is end of an EOL sequence. */
+ def isAtEndOfLine(idx: Int) = charAtIsEOL(idx) {
+ case CR | LF => true
+ case _ => false
+ }
def calculateLineIndices(cs: Array[Char]) = {
val buf = new ArrayBuffer[Int]
buf += 0
- for (i <- 0 until cs.length) if (isLineBreak(i)) buf += i + 1
+ for (i <- 0 until cs.length) if (isAtEndOfLine(i)) buf += i + 1
buf += cs.length // sentinel, so that findLine below works smoother
buf.toArray
}
@@ -150,15 +167,17 @@ class BatchSourceFile(val file : AbstractFile, val content0: Array[Char]) extend
private var lastLine = 0
- /** Convert offset to line in this source file
- * Lines are numbered from 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)
+ def findLine(lo: Int, hi: Int, mid: Int): Int = (
+ if (mid < lo || hi < mid) mid // minimal sanity check - as written this easily went into infinite loopyland
+ else 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/Statistics.scala b/src/reflect/scala/reflect/internal/util/Statistics.scala
index cbd27b0d65..905f1bf26e 100644
--- a/src/reflect/scala/reflect/internal/util/Statistics.scala
+++ b/src/reflect/scala/reflect/internal/util/Statistics.scala
@@ -1,4 +1,5 @@
-package scala.reflect.internal.util
+package scala
+package reflect.internal.util
import scala.collection.mutable
@@ -102,8 +103,8 @@ quant)
for ((_, q) <- qs if q.underlying == q;
r <- q :: q.children.toList if r.prefix.nonEmpty) yield r
- private def showPercent(x: Double, base: Double) =
- if (base == 0) "" else f" (${x / base * 100}%2.1f%%)"
+ private def showPercent(x: Long, base: Long) =
+ if (base == 0) "" else f" (${x.toDouble / base.toDouble * 100}%2.1f%%)"
/** The base trait for quantities.
* Quantities with non-empty prefix are printed in the statistics info.
@@ -132,6 +133,12 @@ quant)
if (this.value < that.value) -1
else if (this.value > that.value) 1
else 0
+ override def equals(that: Any): Boolean =
+ that match {
+ case that: Counter => (this compare that) == 0
+ case _ => false
+ }
+ override def hashCode = value
override def toString = value.toString
}
@@ -155,7 +162,7 @@ quant)
value = value0 + underlying.value - uvalue0
}
override def toString =
- value + showPercent(value, underlying.value)
+ value + showPercent(value.toLong, underlying.value.toLong)
}
class Timer(val prefix: String, val phases: Seq[String]) extends Quantity {
@@ -183,6 +190,12 @@ quant)
if (this.specificNanos < that.specificNanos) -1
else if (this.specificNanos > that.specificNanos) 1
else 0
+ override def equals(that: Any): Boolean =
+ that match {
+ case that: StackableTimer => (this compare that) == 0
+ case _ => false
+ }
+ override def hashCode = specificNanos.##
override def toString = s"${super.toString} aggregate, ${show(specificNanos)} specific"
}
@@ -257,7 +270,6 @@ quant)
def enabled = _enabled
def enabled_=(cond: Boolean) = {
if (cond && !_enabled) {
- val test = new Timer("", Nil)
val start = System.nanoTime()
var total = 0L
for (i <- 1 to 10000) {
diff --git a/src/reflect/scala/reflect/internal/util/StringOps.scala b/src/reflect/scala/reflect/internal/util/StringOps.scala
index 8f6c409e0b..efb8126ff0 100644
--- a/src/reflect/scala/reflect/internal/util/StringOps.scala
+++ b/src/reflect/scala/reflect/internal/util/StringOps.scala
@@ -6,8 +6,12 @@
** |/ **
\* */
+package scala
+package reflect
+package internal
+package util
-package scala.reflect.internal.util
+import scala.compat.Platform.EOL
/** This object provides utility methods to extract elements
* from Strings.
@@ -16,24 +20,32 @@ package scala.reflect.internal.util
* @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 oempty(xs: String*) = xs filterNot (x => x == null || x == "")
+ def ojoin(xs: String*): String = oempty(xs: _*) mkString " "
+ def longestCommonPrefix(xs: List[String]): String = xs match {
+ case Nil => ""
+ case w :: Nil => w
+ case _ =>
+ def lcp(ss: List[String]): String = {
+ val w :: ws = ss
+ if (w == "") ""
+ else if (ws exists (s => s == "" || (s charAt 0) != (w charAt 0))) ""
+ else w.substring(0, 1) + lcp(ss map (_ substring 1))
+ }
+ lcp(xs)
}
- 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
+ /** Like String#trim, but trailing whitespace only.
+ */
+ def trimTrailingSpace(s: String): String = {
+ var end = s.length
+ while (end > 0 && s.charAt(end - 1).isWhitespace)
+ end -= 1
- s.substring(0, idx + 1)
- }
+ if (end == s.length) s
+ else s.substring(0, end)
}
+ /** Breaks the string into lines and strips each line before reassembling. */
+ def trimAllTrailingSpace(s: String): String = s.lines map trimTrailingSpace mkString EOL
def decompose(str: String, sep: Char): List[String] = {
def ws(start: Int): List[String] =
@@ -49,14 +61,6 @@ trait StringOps {
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)
@@ -65,10 +69,6 @@ trait StringOps {
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 {
@@ -81,9 +81,6 @@ trait StringOps {
}
/** Turns a count into a friendly English description if n<=4.
- *
- * @param n ...
- * @return ...
*/
def countAsString(n: Int): String =
n match {
diff --git a/src/reflect/scala/reflect/internal/util/StripMarginInterpolator.scala b/src/reflect/scala/reflect/internal/util/StripMarginInterpolator.scala
index e7579229b2..e622e78d57 100644
--- a/src/reflect/scala/reflect/internal/util/StripMarginInterpolator.scala
+++ b/src/reflect/scala/reflect/internal/util/StripMarginInterpolator.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package internal
package util
@@ -6,7 +7,7 @@ trait StripMarginInterpolator {
def stringContext: StringContext
/**
- * A safe combination of `[[scala.collection.immutable.StringLike#stripMargin]]
+ * A safe combination of [[scala.collection.immutable.StringLike#stripMargin]]
* and [[scala.StringContext#raw]].
*
* The margin of each line is defined by whitespace leading up to a '|' character.
diff --git a/src/reflect/scala/reflect/internal/util/TableDef.scala b/src/reflect/scala/reflect/internal/util/TableDef.scala
index 8e2bcc2ff7..8708442c85 100644
--- a/src/reflect/scala/reflect/internal/util/TableDef.scala
+++ b/src/reflect/scala/reflect/internal/util/TableDef.scala
@@ -1,38 +1,27 @@
-package scala.reflect.internal.util
+package scala
+package reflect.internal.util
import TableDef._
import scala.language.postfixOps
/** A class for representing tabular data in a way that preserves
- * its inner beauty. See Exceptional for an example usage.
+ * its inner beauty.
* 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.
- */
+ // These operators are about all there is to it.
+ /** Appends a column to the table. */
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.
- */
+ // 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 defaultSep(index: Int) = if (index > (cols.size - 2)) "" else " "
+ def sepAfter(i: Int): String = 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))
@@ -59,20 +48,12 @@ class TableDef[T](_cols: Column[T]*) {
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(", ", ", ")")
diff --git a/src/reflect/scala/reflect/internal/util/ThreeValues.scala b/src/reflect/scala/reflect/internal/util/ThreeValues.scala
index f89bd9e199..18410510cb 100644
--- a/src/reflect/scala/reflect/internal/util/ThreeValues.scala
+++ b/src/reflect/scala/reflect/internal/util/ThreeValues.scala
@@ -1,4 +1,5 @@
-package scala.reflect.internal.util
+package scala
+package reflect.internal.util
/** A simple three value type for booleans with an unknown value */
object ThreeValues {
diff --git a/src/reflect/scala/reflect/internal/util/TraceSymbolActivity.scala b/src/reflect/scala/reflect/internal/util/TraceSymbolActivity.scala
index fa83f70f3a..e4a6503184 100644
--- a/src/reflect/scala/reflect/internal/util/TraceSymbolActivity.scala
+++ b/src/reflect/scala/reflect/internal/util/TraceSymbolActivity.scala
@@ -1,4 +1,5 @@
-package scala.reflect.internal
+package scala
+package reflect.internal
package util
import scala.collection.{ mutable, immutable }
@@ -12,13 +13,9 @@ trait TraceSymbolActivity {
if (enabled && 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) {
@@ -44,39 +41,8 @@ trait TraceSymbolActivity {
}
}
- /** 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 lazy val erasurePhase = findPhaseWithName("erasure")
+ private def signature(id: Int) = enteringPhase(erasurePhase)(allSymbols(id).defString)
private def dashes(s: Any): String = ("" + s) map (_ => '-')
private def show(s1: Any, ss: Any*) {
@@ -119,17 +85,9 @@ trait TraceSymbolActivity {
}
println("\n")
}
- private def showFreq[T, U](xs: Traversable[T])(groupFn: T => U, showFn: U => String = (x: U) => "" + x) = {
+ private def showFreq[T, U](xs: Traversable[T])(groupFn: T => U, showFn: U => String) = {
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 (!enabled) return
diff --git a/src/reflect/scala/reflect/internal/util/TriState.scala b/src/reflect/scala/reflect/internal/util/TriState.scala
new file mode 100644
index 0000000000..4074d974d2
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/TriState.scala
@@ -0,0 +1,28 @@
+package scala
+package reflect
+package internal
+package util
+
+import scala.language.implicitConversions
+
+import TriState._
+
+/** A simple true/false/unknown value, for those days when
+ * true and false don't quite partition the space.
+ */
+final class TriState private (val value: Int) extends AnyVal {
+ def isKnown = this != Unknown
+ def booleanValue = this match {
+ case True => true
+ case False => false
+ case _ => sys.error("Not a Boolean value")
+ }
+}
+
+object TriState {
+ implicit def booleanToTriState(b: Boolean): TriState = if (b) True else False
+
+ val Unknown = new TriState(-1)
+ val False = new TriState(0)
+ val True = new TriState(1)
+}
diff --git a/src/reflect/scala/reflect/internal/util/WeakHashSet.scala b/src/reflect/scala/reflect/internal/util/WeakHashSet.scala
index fc12e31360..a9a7c7780d 100644
--- a/src/reflect/scala/reflect/internal/util/WeakHashSet.scala
+++ b/src/reflect/scala/reflect/internal/util/WeakHashSet.scala
@@ -4,7 +4,7 @@ package reflect.internal.util
import java.lang.ref.{WeakReference, ReferenceQueue}
import scala.annotation.tailrec
import scala.collection.generic.Clearable
-import scala.collection.mutable.{Set => mSet}
+import scala.collection.mutable.{Set => MSet}
/**
* A HashSet where the elements are stored weakly. Elements in this set are elligible for GC if no other
@@ -16,8 +16,8 @@ import scala.collection.mutable.{Set => mSet}
* This set implmeentation is not in general thread safe without external concurrency control. However it behaves
* properly when GC concurrently collects elements in this set.
*/
-final class WeakHashSet[A <: AnyRef](val initialCapacity: Int, val loadFactor: Double) extends Set[A] with Function1[A, Boolean] with mSet[A] {
-
+final class WeakHashSet[A <: AnyRef](val initialCapacity: Int, val loadFactor: Double) extends Set[A] with Function1[A, Boolean] with MSet[A] {
+
import WeakHashSet._
def this() = this(initialCapacity = WeakHashSet.defaultInitialCapacity, loadFactor = WeakHashSet.defaultLoadFactor)
@@ -47,7 +47,7 @@ final class WeakHashSet[A <: AnyRef](val initialCapacity: Int, val loadFactor: D
candidate *= 2
}
candidate
- }
+ }
/**
* the underlying table of entries which is an array of Entry linked lists
@@ -65,7 +65,7 @@ final class WeakHashSet[A <: AnyRef](val initialCapacity: Int, val loadFactor: D
* find the bucket associated with an elements's hash code
*/
private[this] def bucketFor(hash: Int): Int = {
- // spread the bits around to try to avoid accidental collisions using the
+ // spread the bits around to try to avoid accidental collisions using the
// same algorithm as java.util.HashMap
var h = hash
h ^= h >>> 20 ^ h >>> 12
@@ -98,7 +98,7 @@ final class WeakHashSet[A <: AnyRef](val initialCapacity: Int, val loadFactor: D
def poll(): Entry[A] = queue.poll().asInstanceOf[Entry[A]]
@tailrec
- def queueLoop {
+ def queueLoop(): Unit = {
val stale = poll()
if (stale != null) {
val bucket = bucketFor(stale.hash)
@@ -109,11 +109,11 @@ final class WeakHashSet[A <: AnyRef](val initialCapacity: Int, val loadFactor: D
linkedListLoop(null, table(bucket))
- queueLoop
+ queueLoop()
}
}
-
- queueLoop
+
+ queueLoop()
}
/**
@@ -123,7 +123,7 @@ final class WeakHashSet[A <: AnyRef](val initialCapacity: Int, val loadFactor: D
val oldTable = table
table = new Array[Entry[A]](oldTable.size * 2)
threshhold = computeThreshHold
-
+
@tailrec
def tableLoop(oldBucket: Int): Unit = if (oldBucket < oldTable.size) {
@tailrec
@@ -225,7 +225,7 @@ final class WeakHashSet[A <: AnyRef](val initialCapacity: Int, val loadFactor: D
def +=(elem: A) = this + elem
// from scala.reflect.interanl.Set
- override def addEntry(x: A) { this += x }
+ override def addEntry(x: A) { this += x }
// remove an element from this set and return this set
override def -(elem: A): this.type = elem match {
@@ -274,6 +274,7 @@ final class WeakHashSet[A <: AnyRef](val initialCapacity: Int, val loadFactor: D
override def foreach[U](f: A => U): Unit = iterator foreach f
+ // It has the `()` because iterator runs `removeStaleEntries()`
override def toList(): List[A] = iterator.toList
// Iterator over all the elements in this set in no particular order
@@ -292,7 +293,7 @@ final class WeakHashSet[A <: AnyRef](val initialCapacity: Int, val loadFactor: D
*/
private[this] var entry: Entry[A] = null
- /**
+ /**
* the element that will be the result of the next call to next()
*/
private[this] var lookaheadelement: A = null.asInstanceOf[A]
@@ -339,7 +340,7 @@ final class WeakHashSet[A <: AnyRef](val initialCapacity: Int, val loadFactor: D
* the entries must be stable. If any are garbage collected during validation
* then an assertion may inappropriately fire.
*/
- def fullyValidate {
+ def fullyValidate: Unit = {
var computedCount = 0
var bucket = 0
while (bucket < table.size) {
@@ -383,34 +384,9 @@ final class WeakHashSet[A <: AnyRef](val initialCapacity: Int, val loadFactor: D
* Number of buckets in the table
*/
def bucketsCount: Int = table.size
-
- /**
- * Number of buckets that don't hold anything
- */
- def emptyBucketsCount = bucketsCount - fullBucketsCount
-
- /**
- * Number of elements that are in collision. Useful for diagnosing performance issues.
- */
- def collisionsCount = size - (fullBucketsCount - collisionBucketsCount)
-
- /**
- * A map from a count of elements to the number of buckets with that count
- */
- def elementCountDistribution = table map linkedListSize groupBy identity map {case (size, list) => (size, list.size)}
-
- private def linkedListSize(entry: Entry[A]) = {
- var e = entry
- var count = 0
- while (e != null) {
- count += 1
- e = e.tail
- }
- count
- }
}
- private[util] def diagnostics = new Diagnostics
+ private[util] def diagnostics = new Diagnostics
}
/**
@@ -427,4 +403,4 @@ object WeakHashSet {
val defaultLoadFactor = .75
def apply[A <: AnyRef](initialCapacity: Int = WeakHashSet.defaultInitialCapacity, loadFactor: Double = WeakHashSet.defaultLoadFactor) = new WeakHashSet[A](initialCapacity, defaultLoadFactor)
-}
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/internal/util/package.scala b/src/reflect/scala/reflect/internal/util/package.scala
index 6d77235db6..3618c150ca 100644
--- a/src/reflect/scala/reflect/internal/util/package.scala
+++ b/src/reflect/scala/reflect/internal/util/package.scala
@@ -1,7 +1,42 @@
-package scala.reflect
+package scala
+package reflect
package internal
+import scala.language.existentials // SI-6541
+
package object util {
+ import StringOps.longestCommonPrefix
+
+ // An allocation-avoiding reusable instance of the so-common List(Nil).
+ val ListOfNil: List[List[Nothing]] = Nil :: Nil
+
+ def andFalse(body: Unit): Boolean = false
+
+ // Shorten a name like Symbols$FooSymbol to FooSymbol.
+ private def shortenName(name: String): String = {
+ if (name == "") return ""
+ val segments = (name split '$').toList
+ val last = segments.last
+
+ if (last.length == 0)
+ segments takeRight 2 mkString "$"
+ else
+ last
+ }
+
+ def shortClassOfInstance(x: AnyRef): String = shortClass(x.getClass)
+ def shortClass(clazz: Class[_]): String = {
+ val name: String = (clazz.getName split '.').last
+ def isModule = name endsWith "$" // object
+ def isAnon = (name split '$').last forall (_.isDigit) // anonymous class
+
+ if (isModule)
+ (name split '$' filterNot (_ == "")).last + "$"
+ else if (isAnon)
+ clazz.getSuperclass :: clazz.getInterfaces.toList map (c => shortClass(c)) mkString " with "
+ else
+ shortenName(name)
+ }
/**
* Adds the `sm` String interpolator to a [[scala.StringContext]].
*/
diff --git a/src/reflect/scala/reflect/io/AbstractFile.scala b/src/reflect/scala/reflect/io/AbstractFile.scala
index 15befb67f1..ac1159b2ac 100644
--- a/src/reflect/scala/reflect/io/AbstractFile.scala
+++ b/src/reflect/scala/reflect/io/AbstractFile.scala
@@ -4,19 +4,21 @@
*/
-package scala.reflect
+package scala
+package reflect
package io
-import java.io.{ FileOutputStream, IOException, InputStream, OutputStream, BufferedOutputStream }
+import java.io.{ FileOutputStream, IOException, InputStream, OutputStream, BufferedOutputStream, ByteArrayOutputStream }
import java.io.{ File => JFile }
import java.net.URL
import scala.collection.mutable.ArrayBuffer
+import scala.reflect.internal.util.Statistics
/**
* An abstraction over files for use in the reflection/compiler libraries.
- *
+ *
* ''Note: This library is considered experimental and should not be used unless you know what you are doing.''
- *
+ *
* @author Philippe Altherr
* @version 1.0, 23/03/2004
*/
@@ -27,7 +29,7 @@ object AbstractFile {
/**
* If the specified File exists and is a regular file, returns an
- * abstract regular file backed by it. Otherwise, returns <code>null</code>.
+ * abstract regular file backed by it. Otherwise, returns `null`.
*/
def getFile(file: File): AbstractFile =
if (file.isFile) new PlainFile(file) else null
@@ -38,10 +40,7 @@ object AbstractFile {
/**
* 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 ...
+ * backed by it. Otherwise, returns `null`.
*/
def getDirectory(file: File): AbstractFile =
if (file.isDirectory) new PlainFile(file)
@@ -51,15 +50,14 @@ object AbstractFile {
/**
* 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 ...
+ * `null`.
*/
def getURL(url: URL): AbstractFile = {
if (url == null || !Path.isExtensionJarOrZip(url.getPath)) null
else ZipArchive fromURL url
}
+
+ def getResources(url: URL): AbstractFile = ZipArchive fromManifestURL url
}
/**
@@ -80,12 +78,12 @@ object AbstractFile {
* </p>
* <p>
* The interface does <b>not</b> allow to access the content.
- * The class <code>symtab.classfile.AbstractFileReader</code> accesses
+ * The class `symtab.classfile.AbstractFileReader` 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>.
+ * all other cases, the class `SourceFile` is used, which honors
+ * `global.settings.encoding.value`.
* </p>
- *
+ *
* ''Note: This library is considered experimental and should not be used unless you know what you are doing.''
*/
abstract class AbstractFile extends Iterable[AbstractFile] {
@@ -116,7 +114,10 @@ abstract class AbstractFile extends Iterable[AbstractFile] {
def underlyingSource: Option[AbstractFile] = None
/** Does this abstract file denote an existing file? */
- def exists: Boolean = (file eq null) || file.exists
+ def exists: Boolean = {
+ if (Statistics.canEnable) Statistics.incCounter(IOStats.fileExistsCount)
+ (file eq null) || file.exists
+ }
/** Does this abstract file represent something which can contain classfiles? */
def isClassContainer = isDirectory || (file != null && (extension == "jar" || extension == "zip"))
@@ -130,6 +131,9 @@ abstract class AbstractFile extends Iterable[AbstractFile] {
/** Is this abstract file a directory? */
def isDirectory: Boolean
+ /** Does this abstract file correspond to something on-disk? */
+ def isVirtual: Boolean = false
+
/** Returns the time that this abstract file was last modified. */
def lastModified: Long
@@ -148,7 +152,7 @@ abstract class AbstractFile extends Iterable[AbstractFile] {
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
+ * warning: use `Global.getSourceFile()` to use the proper
* encoding when converting to the char array.
*/
@throws(classOf[IOException])
@@ -159,24 +163,36 @@ abstract class AbstractFile extends Iterable[AbstractFile] {
@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
+ sizeOption match {
+ case Some(size) =>
+ var rest = size
+ 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
+ case None =>
+ val out = new ByteArrayOutputStream()
+ var c = in.read()
+ while(c != -1) {
+ out.write(c)
+ c = in.read()
+ }
+ in.close()
+ out.toByteArray()
}
- 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
+ * name. If there is no such file, returns `null`. The argument
+ * `directory` tells whether to look for a directory or
* a regular file.
*/
def lookupName(name: String, directory: Boolean): AbstractFile
@@ -186,19 +202,6 @@ abstract class AbstractFile extends Iterable[AbstractFile] {
*/
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.
*/
@@ -243,7 +246,7 @@ abstract class AbstractFile extends Iterable[AbstractFile] {
*/
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)
+ fileOrSubdirectoryNamed(name, isDir = false)
}
/**
@@ -252,7 +255,7 @@ abstract class AbstractFile extends Iterable[AbstractFile] {
*/
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)
+ fileOrSubdirectoryNamed(name, isDir = true)
}
protected def unsupported(): Nothing = unsupported(null)
diff --git a/src/reflect/scala/reflect/io/Directory.scala b/src/reflect/scala/reflect/io/Directory.scala
index c040d1eac5..2b965e6d69 100644
--- a/src/reflect/scala/reflect/io/Directory.scala
+++ b/src/reflect/scala/reflect/io/Directory.scala
@@ -6,7 +6,8 @@
** |/ **
\* */
-package scala.reflect
+package scala
+package reflect
package io
import java.io.{ File => JFile }
@@ -14,12 +15,10 @@ import java.io.{ File => JFile }
* ''Note: This library is considered experimental and should not be used unless you know what you are doing.''
*/
object Directory {
- import scala.util.Properties.{ tmpDir, userHome, userDir }
+ import scala.util.Properties.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
@@ -30,20 +29,18 @@ object Directory {
path.createDirectory()
}
}
-import Path._
/** An abstraction for directories.
*
* @author Paul Phillips
* @since 2.8
- *
+ *
* ''Note: This is library is considered experimental and should not be used unless you know what you are doing.''
*/
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.
@@ -60,7 +57,6 @@ class Directory(jfile: JFile) extends Path(jfile) {
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
@@ -70,10 +66,4 @@ class Directory(jfile: JFile) extends Path(jfile) {
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/reflect/io/File.scala b/src/reflect/scala/reflect/io/File.scala
index 736ba5d51e..a9c6807e88 100644
--- a/src/reflect/scala/reflect/io/File.scala
+++ b/src/reflect/scala/reflect/io/File.scala
@@ -7,13 +7,16 @@
\* */
-package scala.reflect
+package scala
+package reflect
package io
import java.io.{
FileInputStream, FileOutputStream, BufferedReader, BufferedWriter, InputStreamReader, OutputStreamWriter,
- BufferedInputStream, BufferedOutputStream, IOException, PrintStream, PrintWriter, Closeable => JCloseable }
-import java.io.{ File => JFile }
+ BufferedInputStream, BufferedOutputStream, IOException, PrintStream, PrintWriter, Closeable => JCloseable,
+ File => JFile
+}
+
import java.nio.channels.{ Channel, FileChannel }
import scala.io.Codec
import scala.language.{reflectiveCalls, implicitConversions}
@@ -22,8 +25,7 @@ import scala.language.{reflectiveCalls, implicitConversions}
*/
object File {
def pathSeparator = java.io.File.pathSeparator
- def separator = java.io.File.separator
-
+ 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.
@@ -32,41 +34,7 @@ object File {
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
@@ -76,19 +44,17 @@ import Path._
*
* @author Paul Phillips
* @since 2.8
- *
+ *
* ''Note: This is library is considered experimental and should not be used unless you know what you are doing.''
*/
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
@@ -99,26 +65,22 @@ class File(jfile: JFile)(implicit constructorCodec: Codec) extends Path(jfile) w
/** 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(): BufferedWriter = bufferedWriter(append = 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 = {
@@ -127,12 +89,6 @@ class File(jfile: JFile)(implicit constructorCodec: Codec) extends Path(jfile) w
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 _)
@@ -150,39 +106,6 @@ class File(jfile: JFile)(implicit constructorCodec: Codec) extends Path(jfile) w
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 = {
diff --git a/src/reflect/scala/reflect/io/FileOperationException.scala b/src/reflect/scala/reflect/io/FileOperationException.scala
index 13a1322798..fdfe0234e0 100644
--- a/src/reflect/scala/reflect/io/FileOperationException.scala
+++ b/src/reflect/scala/reflect/io/FileOperationException.scala
@@ -7,7 +7,8 @@
\* */
-package scala.reflect
+package scala
+package reflect
package io
/** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */
case class FileOperationException(msg: String) extends RuntimeException(msg)
diff --git a/src/reflect/scala/reflect/io/IOStats.scala b/src/reflect/scala/reflect/io/IOStats.scala
new file mode 100644
index 0000000000..71f8be330d
--- /dev/null
+++ b/src/reflect/scala/reflect/io/IOStats.scala
@@ -0,0 +1,32 @@
+package scala
+package reflect.io
+
+import scala.reflect.internal.util.Statistics
+
+// Due to limitations in the Statistics machinery, these are only
+// reported if this patch is applied.
+//
+// --- a/src/reflect/scala/reflect/internal/util/Statistics.scala
+// +++ b/src/reflect/scala/reflect/internal/util/Statistics.scala
+// @@ -109,7 +109,7 @@ quant)
+// * Quantities with non-empty prefix are printed in the statistics info.
+// */
+// trait Quantity {
+// - if (enabled && prefix.nonEmpty) {
+// + if (prefix.nonEmpty) {
+// val key = s"${if (underlying != this) underlying.prefix else ""}/$prefix"
+// qs(key) = this
+// }
+// @@ -243,7 +243,7 @@ quant)
+// *
+// * to remove all Statistics code from build
+// */
+// - final val canEnable = _enabled
+// + final val canEnable = true // _enabled
+//
+// We can commit this change as the first diff reverts a fix for an IDE memory leak.
+private[io] object IOStats {
+ val fileExistsCount = Statistics.newCounter("# File.exists calls")
+ val fileIsDirectoryCount = Statistics.newCounter("# File.isDirectory calls")
+ val fileIsFileCount = Statistics.newCounter("# File.isFile calls")
+}
diff --git a/src/reflect/scala/reflect/io/NoAbstractFile.scala b/src/reflect/scala/reflect/io/NoAbstractFile.scala
index 8c88d3abf6..18eca7698d 100644
--- a/src/reflect/scala/reflect/io/NoAbstractFile.scala
+++ b/src/reflect/scala/reflect/io/NoAbstractFile.scala
@@ -3,15 +3,15 @@
* @author Paul Phillips
*/
-package scala.reflect
+package scala
+package reflect
package io
import java.io.InputStream
-import java.io.{ File => JFile }
/** A distinguished object so you can avoid both null
* and Option.
- *
+ *
* ''Note: This library is considered experimental and should not be used unless you know what you are doing.''
*/
object NoAbstractFile extends AbstractFile {
@@ -19,9 +19,10 @@ object NoAbstractFile extends AbstractFile {
def container: AbstractFile = this
def create(): Unit = ???
def delete(): Unit = ???
- def file: JFile = null
+ def file: java.io.File = null
def input: InputStream = null
def isDirectory: Boolean = false
+ override def isVirtual: Boolean = true
def iterator: Iterator[AbstractFile] = Iterator.empty
def lastModified: Long = 0L
def lookupName(name: String, directory: Boolean): AbstractFile = null
@@ -30,4 +31,5 @@ object NoAbstractFile extends AbstractFile {
def output: java.io.OutputStream = null
def path: String = ""
override def toByteArray = Array[Byte]()
+ override def toString = "<no file>"
}
diff --git a/src/reflect/scala/reflect/io/Path.scala b/src/reflect/scala/reflect/io/Path.scala
index 36fdc04db4..15fce953f2 100644
--- a/src/reflect/scala/reflect/io/Path.scala
+++ b/src/reflect/scala/reflect/io/Path.scala
@@ -3,16 +3,17 @@
* @author Paul Phillips
*/
-package scala.reflect
+package scala
+package reflect
package io
import java.io.{
FileInputStream, FileOutputStream, BufferedReader, BufferedWriter, InputStreamReader, OutputStreamWriter,
- BufferedInputStream, BufferedOutputStream, RandomAccessFile }
-import java.io.{ File => JFile }
+ BufferedInputStream, BufferedOutputStream, RandomAccessFile, File => JFile }
import java.net.{ URI, URL }
import scala.util.Random.alphanumeric
import scala.language.implicitConversions
+import scala.reflect.internal.util.Statistics
/** An abstraction for filesystem paths. The differences between
* Path, File, and Directory are primarily to communicate intent.
@@ -27,7 +28,7 @@ import scala.language.implicitConversions
*
* @author Paul Phillips
* @since 2.8
- *
+ *
* ''Note: This library is considered experimental and should not be used unless you know what you are doing.''
*/
object Path {
@@ -49,32 +50,28 @@ object Path {
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)
+ def apply(jfile: JFile): Path = try {
+ def isFile = {
+ if (Statistics.canEnable) Statistics.incCounter(IOStats.fileIsFileCount)
+ jfile.isFile
+ }
+
+ def isDirectory = {
+ if (Statistics.canEnable) Statistics.incCounter(IOStats.fileIsDirectoryCount)
+ jfile.isDirectory
+ }
+
+ if (isFile) new File(jfile)
+ else if (isDirectory) new Directory(jfile)
else new Path(jfile)
+ } catch { case ex: SecurityException => new Path(jfile) }
/** Avoiding any shell/path issues by only using alphanumerics. */
private[io] def randomPrefix = alphanumeric take 6 mkString ""
@@ -84,19 +81,13 @@ import Path._
/** The Path constructor is private so we can enforce some
* semantics regarding how a Path might relate to the world.
- *
+ *
* ''Note: This library is considered experimental and should not be used unless you know what you are doing.''
*/
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)
@@ -104,6 +95,7 @@ class Path private[io] (val jfile: JFile) {
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.
*/
@@ -136,7 +128,6 @@ class Path private[io] (val jfile: JFile) {
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) = {
@@ -152,9 +143,8 @@ class Path private[io] (val jfile: JFile) {
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
*/
@@ -185,10 +175,6 @@ class Path private[io] (val jfile: JFile) {
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
@@ -212,23 +198,28 @@ class Path private[io] (val jfile: JFile) {
// 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 exists = {
+ if (Statistics.canEnable) Statistics.incCounter(IOStats.fileExistsCount)
+ try jfile.exists() catch { case ex: SecurityException => false }
+ }
- def isFile = jfile.isFile()
- def isDirectory = jfile.isDirectory()
+ def isFile = {
+ if (Statistics.canEnable) Statistics.incCounter(IOStats.fileIsFileCount)
+ try jfile.isFile() catch { case ex: SecurityException => false }
+ }
+ def isDirectory = {
+ if (Statistics.canEnable) Statistics.incCounter(IOStats.fileIsDirectoryCount)
+ try jfile.isDirectory() catch { case ex: SecurityException => jfile.getPath == "." }
+ }
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
@@ -248,7 +239,6 @@ class Path private[io] (val jfile: 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!
@@ -270,16 +260,6 @@ class Path private[io] (val jfile: JFile) {
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
diff --git a/src/reflect/scala/reflect/io/PlainFile.scala b/src/reflect/scala/reflect/io/PlainFile.scala
index 82b0568657..8f24d84488 100644
--- a/src/reflect/scala/reflect/io/PlainFile.scala
+++ b/src/reflect/scala/reflect/io/PlainFile.scala
@@ -3,23 +3,12 @@
* @author Martin Odersky
*/
-
-package scala.reflect
+package scala
+package reflect
package io
import java.io.{ FileInputStream, FileOutputStream, IOException }
-import PartialFunction._
-/** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */
-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
-}
+
/** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */
class PlainDirectory(givenPath: Directory) extends PlainFile(givenPath) {
override def isDirectory = true
@@ -28,7 +17,7 @@ class PlainDirectory(givenPath: Directory) extends PlainFile(givenPath) {
}
/** This class implements an abstract file backed by a File.
- *
+ *
* ''Note: This library is considered experimental and should not be used unless you know what you are doing.''
*/
class PlainFile(val givenPath: Path) extends AbstractFile {
@@ -54,7 +43,7 @@ class PlainFile(val givenPath: Path) extends AbstractFile {
override def sizeOption = Some(givenPath.length.toInt)
override def toString = path
- override def hashCode(): Int = fpath.hashCode
+ override def hashCode(): Int = fpath.hashCode()
override def equals(that: Any): Boolean = that match {
case x: PlainFile => fpath == x.fpath
case _ => false
@@ -68,8 +57,14 @@ class PlainFile(val givenPath: Path) extends AbstractFile {
/** Returns all abstract subfiles of this abstract directory. */
def iterator: Iterator[AbstractFile] = {
+ // Optimization: Assume that the file was not deleted and did not have permissions changed
+ // between the call to `list` and the iteration. This saves a call to `exists`.
+ def existsFast(path: Path) = path match {
+ case (_: Directory | _: io.File) => true
+ case _ => path.exists
+ }
if (!isDirectory) Iterator.empty
- else givenPath.toDirectory.list filter (_.exists) map (new PlainFile(_))
+ else givenPath.toDirectory.list filter existsFast map (new PlainFile(_))
}
/**
@@ -77,10 +72,6 @@ class PlainFile(val givenPath: Path) extends AbstractFile {
* 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
diff --git a/src/reflect/scala/reflect/io/Streamable.scala b/src/reflect/scala/reflect/io/Streamable.scala
index 61ec8a4c23..aa47947672 100644
--- a/src/reflect/scala/reflect/io/Streamable.scala
+++ b/src/reflect/scala/reflect/io/Streamable.scala
@@ -3,7 +3,8 @@
* @author Paul Phillips
*/
-package scala.reflect
+package scala
+package reflect
package io
import java.net.{ URI, URL }
@@ -17,14 +18,14 @@ import Path.fail
*
* @author Paul Phillips
* @since 2.8
- *
+ *
* ''Note: This library is considered experimental and should not be used unless you know what you are doing.''
*/
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.
- *
+ *
* ''Note: This library is considered experimental and should not be used unless you know what you are doing.''
*/
trait Bytes {
@@ -69,7 +70,7 @@ object Streamable {
}
/** For objects which can be viewed as Chars.
- *
+ *
* ''Note: This library is considered experimental and should not be used unless you know what you are doing.''
*/
trait Chars extends Bytes {
@@ -81,7 +82,6 @@ object Streamable {
*/
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)
@@ -89,8 +89,7 @@ object Streamable {
/** Obtains an InputStreamReader wrapped around a FileInputStream.
*/
- def reader(): InputStreamReader = reader(creationCodec)
- def reader(codec: Codec): InputStreamReader = new InputStreamReader(inputStream, codec.charSet)
+ def reader(codec: Codec): InputStreamReader = new InputStreamReader(inputStream(), codec.charSet)
/** Wraps a BufferedReader around the result of reader().
*/
@@ -108,7 +107,10 @@ object Streamable {
/** Convenience function to import entire file into a String.
*/
def slurp(): String = slurp(creationCodec)
- def slurp(codec: Codec) = chars(codec).mkString
+ def slurp(codec: Codec) = {
+ val src = chars(codec)
+ try src.mkString finally src.close() // Always Be Closing
+ }
}
/** Call a function on something Closeable, finally closing it. */
@@ -117,7 +119,9 @@ object Streamable {
finally stream.close()
def bytes(is: => InputStream): Array[Byte] =
- (new Bytes { def inputStream() = is }).toByteArray
+ (new Bytes {
+ def inputStream() = is
+ }).toByteArray()
def slurp(is: => InputStream)(implicit codec: Codec): String =
new Chars { def inputStream() = is } slurp codec
diff --git a/src/reflect/scala/reflect/io/VirtualDirectory.scala b/src/reflect/scala/reflect/io/VirtualDirectory.scala
index 78713c2ae0..aa6ceaa09f 100644
--- a/src/reflect/scala/reflect/io/VirtualDirectory.scala
+++ b/src/reflect/scala/reflect/io/VirtualDirectory.scala
@@ -2,7 +2,8 @@
* Copyright 2005-2013 LAMP/EPFL
*/
-package scala.reflect
+package scala
+package reflect
package io
import scala.collection.mutable
@@ -11,7 +12,7 @@ import scala.collection.mutable
* An in-memory directory.
*
* @author Lex Spoon
- *
+ *
* ''Note: This library is considered experimental and should not be used unless you know what you are doing.''
*/
class VirtualDirectory(val name: String, maybeContainer: Option[VirtualDirectory])
@@ -26,22 +27,23 @@ extends AbstractFile {
def container = maybeContainer.get
def isDirectory = true
- var lastModified: Long = System.currentTimeMillis
+ override def isVirtual = true
+ val 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 }
+ def create() { unsupported() }
/** Delete the underlying file or directory (recursively). */
- def delete() { unsupported }
+ 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
+ def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile = unsupported()
private val files = mutable.Map.empty[String, AbstractFile]
@@ -53,20 +55,20 @@ extends AbstractFile {
(files get name filter (_.isDirectory == directory)).orNull
override def fileNamed(name: String): AbstractFile =
- Option(lookupName(name, false)) getOrElse {
+ Option(lookupName(name, directory = false)) getOrElse {
val newFile = new VirtualFile(name, path+'/'+name)
files(name) = newFile
newFile
}
override def subdirectoryNamed(name: String): AbstractFile =
- Option(lookupName(name, true)) getOrElse {
+ Option(lookupName(name, directory = true)) getOrElse {
val dir = new VirtualDirectory(name, Some(this))
files(name) = dir
dir
}
def clear() {
- files.clear();
+ files.clear()
}
}
diff --git a/src/reflect/scala/reflect/io/VirtualFile.scala b/src/reflect/scala/reflect/io/VirtualFile.scala
index 95f4429fad..45f38db745 100644
--- a/src/reflect/scala/reflect/io/VirtualFile.scala
+++ b/src/reflect/scala/reflect/io/VirtualFile.scala
@@ -3,18 +3,17 @@
* @author Martin Odersky
*/
-
-package scala.reflect
+package scala
+package reflect
package io
-import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, InputStream, OutputStream }
-import java.io.{ File => JFile }
+import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, InputStream, OutputStream, File => JFile }
/** This class implements an in-memory file.
*
* @author Philippe Altherr
* @version 1.0, 23/03/2004
- *
+ *
* ''Note: This library is considered experimental and should not be used unless you know what you are doing.''
*/
class VirtualFile(val name: String, override val path: String) extends AbstractFile {
@@ -33,20 +32,16 @@ class VirtualFile(val name: String, override val path: String) extends AbstractF
case _ => false
}
- //########################################################################
- // Private data
private var content = Array.emptyByteArray
- //########################################################################
- // Public Methods
def absolute = this
/** Returns null. */
- final def file: JFile = null
+ def file: JFile = null
- override def sizeOption: Option[Int] = Some(content.size)
+ override def sizeOption: Option[Int] = Some(content.length)
- def input : InputStream = new ByteArrayInputStream(content);
+ def input : InputStream = new ByteArrayInputStream(content)
override def output: OutputStream = {
new ByteArrayOutputStream() {
@@ -62,10 +57,16 @@ class VirtualFile(val name: String, override val path: String) extends AbstractF
/** Is this abstract file a directory? */
def isDirectory: Boolean = false
+ /** @inheritdoc */
+ override def isVirtual: Boolean = true
+
+ // private var _lastModified: Long = 0
+ // _lastModified
+
/** 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
+ // !!! Except it doesn't - it's private and never set - so I replaced it
+ // with constant 0 to save the field.
+ def lastModified: Long = 0
/** Returns all abstract subfiles of this abstract directory. */
def iterator: Iterator[AbstractFile] = {
@@ -74,20 +75,16 @@ class VirtualFile(val name: String, override val path: String) extends AbstractF
}
/** Does this abstract file denote an existing file? */
- def create() { unsupported }
+ def create() { unsupported() }
/** Delete the underlying file or directory (recursively). */
- def delete() { unsupported }
+ 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 + "'")
@@ -97,7 +94,5 @@ class VirtualFile(val name: String, override val path: String) extends AbstractF
/** Returns an abstract file with the given name. It does not
* check that it exists.
*/
- def lookupNameUnchecked(name: String, directory: Boolean) = unsupported
-
- //########################################################################
+ def lookupNameUnchecked(name: String, directory: Boolean) = unsupported()
}
diff --git a/src/reflect/scala/reflect/io/ZipArchive.scala b/src/reflect/scala/reflect/io/ZipArchive.scala
index 3b57721e89..8260189459 100644
--- a/src/reflect/scala/reflect/io/ZipArchive.scala
+++ b/src/reflect/scala/reflect/io/ZipArchive.scala
@@ -3,14 +3,17 @@
* @author Paul Phillips
*/
-package scala.reflect
+package scala
+package reflect
package io
import java.net.URL
-import java.io.{ IOException, InputStream, ByteArrayInputStream }
+import java.io.{ IOException, InputStream, ByteArrayInputStream, FilterInputStream }
import java.io.{ File => JFile }
import java.util.zip.{ ZipEntry, ZipFile, ZipInputStream }
+import java.util.jar.Manifest
import scala.collection.{ immutable, mutable }
+import scala.collection.convert.WrapAsScala.asScalaIterator
import scala.annotation.tailrec
/** An abstraction for zip files and streams. Everything is written the way
@@ -20,13 +23,10 @@ import scala.annotation.tailrec
* @author Philippe Altherr (original version)
* @author Paul Phillips (this one)
* @version 2.0,
- *
+ *
* ''Note: This library is considered experimental and should not be used unless you know what you are doing.''
*/
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.
@@ -41,10 +41,11 @@ object ZipArchive {
* @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)
+ def fromManifestURL(url: URL): AbstractFile = new ManifestResources(url)
+
+ private def dirName(path: String) = splitPath(path, front = true)
+ private def baseName(path: String) = splitPath(path, front = 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
@@ -65,13 +66,13 @@ abstract class ZipArchive(override val file: JFile) extends AbstractFile with Eq
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
+ 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 =>
@@ -79,7 +80,6 @@ abstract class ZipArchive(override val file: JFile) extends AbstractFile with Eq
else Iterator(f)
}
}
- def deepIterator = walkIterator(iterator)
/** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */
sealed abstract class Entry(path: String) extends VirtualFile(baseName(path), path) {
// have to keep this name for compat with sbt's compiler-interface
@@ -126,7 +126,11 @@ abstract class ZipArchive(override val file: JFile) extends AbstractFile with Eq
/** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */
final class FileZipArchive(file: JFile) extends ZipArchive(file) {
def iterator: Iterator[Entry] = {
- val zipFile = new ZipFile(file)
+ val zipFile = try {
+ new ZipFile(file)
+ } catch {
+ case ioe: IOException => throw new IOException("Error accessing " + file.getPath, ioe)
+ }
val root = new DirEntry("/")
val dirs = mutable.HashMap[String, DirEntry]("/" -> root)
val enum = zipFile.entries()
@@ -232,3 +236,63 @@ final class URLZipArchive(val url: URL) extends ZipArchive(null) {
case _ => false
}
}
+
+final class ManifestResources(val url: URL) extends ZipArchive(null) {
+ def iterator = {
+ val root = new DirEntry("/")
+ val dirs = mutable.HashMap[String, DirEntry]("/" -> root)
+ val manifest = new Manifest(input)
+ val iter = manifest.getEntries().keySet().iterator().filter(_.endsWith(".class")).map(new ZipEntry(_))
+
+ while (iter.hasNext) {
+ val zipEntry = iter.next()
+ val dir = getDir(dirs, zipEntry)
+ if (zipEntry.isDirectory) dir
+ else {
+ class FileEntry() extends Entry(zipEntry.getName) {
+ override def lastModified = zipEntry.getTime()
+ override def input = resourceInputStream(path)
+ override def sizeOption = None
+ }
+ val f = new FileEntry()
+ dir.entries(f.name) = f
+ }
+ }
+
+ try root.iterator
+ finally dirs.clear()
+ }
+
+ def name = path
+ def path: String = {
+ val s = url.getPath
+ val n = s.lastIndexOf('!')
+ s.substring(0, n)
+ }
+ def input = url.openStream()
+ def lastModified =
+ try url.openConnection().getLastModified()
+ catch { case _: IOException => 0 }
+
+ override def canEqual(other: Any) = other.isInstanceOf[ManifestResources]
+ override def hashCode() = url.hashCode
+ override def equals(that: Any) = that match {
+ case x: ManifestResources => url == x.url
+ case _ => false
+ }
+
+ private def resourceInputStream(path: String): InputStream = {
+ new FilterInputStream(null) {
+ override def read(): Int = {
+ if(in == null) in = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
+ if(in == null) throw new RuntimeException(path + " not found")
+ super.read();
+ }
+
+ override def close(): Unit = {
+ super.close();
+ in = null;
+ }
+ }
+ }
+}
diff --git a/src/reflect/scala/reflect/macros/Aliases.scala b/src/reflect/scala/reflect/macros/Aliases.scala
index 92d76f4370..64819a8601 100644
--- a/src/reflect/scala/reflect/macros/Aliases.scala
+++ b/src/reflect/scala/reflect/macros/Aliases.scala
@@ -1,14 +1,15 @@
-package scala.reflect
+package scala
+package reflect
package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that defines shorthands for the
+ * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that defines shorthands for the
* most frequently used types and functions of the underlying compiler universe.
*/
trait Aliases {
- self: Context =>
+ self: blackbox.Context =>
/** The type of symbols representing declarations. */
type Symbol = universe.Symbol
@@ -39,10 +40,16 @@ trait Aliases {
/** The type of tree modifiers. */
type Modifiers = universe.Modifiers
- /** The type of compilation runs. */
+ /** The type of compilation runs.
+ * @see [[scala.reflect.macros.Enclosures]]
+ */
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
type Run = universe.Run
- /** The type of compilation units. */
+ /** The type of compilation units.
+ * @see [[scala.reflect.macros.Enclosures]]
+ */
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
type CompilationUnit = universe.CompilationUnit
/** Expr wraps an abstract syntax tree and tags it with its type. */
@@ -109,4 +116,9 @@ trait Aliases {
* Shortcut for `implicitly[TypeTag[T]].tpe`
*/
def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpe
+
+ /**
+ * Type symbol of `x` as derived from a type tag.
+ */
+ def symbolOf[T: WeakTypeTag]: universe.TypeSymbol = universe.symbolOf[T]
}
diff --git a/src/reflect/scala/reflect/macros/Attachments.scala b/src/reflect/scala/reflect/macros/Attachments.scala
index 007df3b6e2..5ccdc15a03 100644
--- a/src/reflect/scala/reflect/macros/Attachments.scala
+++ b/src/reflect/scala/reflect/macros/Attachments.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package macros
/**
@@ -40,6 +41,10 @@ abstract class Attachments { self =>
def get[T: ClassTag]: Option[T] =
(all filter matchesTag[T]).headOption.asInstanceOf[Option[T]]
+ /** Check underlying payload contains an instance of type `T`. */
+ def contains[T: ClassTag]: Boolean =
+ !isEmpty && (all exists matchesTag[T])
+
/** Creates a copy of this attachment with the payload slot of T added/updated with the provided value.
* Replaces an existing payload of the same type, if exists.
*/
@@ -52,13 +57,14 @@ abstract class Attachments { self =>
if (newAll.isEmpty) pos.asInstanceOf[Attachments { type Pos = self.Pos }]
else new NonemptyAttachments[Pos](this.pos, newAll)
}
+
+ def isEmpty: Boolean = true
}
// SI-7018: This used to be an inner class of `Attachments`, but that led to a memory leak in the
// IDE via $outer pointers.
-// Forward compatibility note: This class used to be Attachments$NonemptyAttachments.
-// However it's private, therefore it transcends the compatibility policy for 2.10.x.
private final class NonemptyAttachments[P >: Null](override val pos: P, override val all: Set[Any]) extends Attachments {
type Pos = P
def withPos(newPos: Pos) = new NonemptyAttachments(newPos, all)
+ override def isEmpty: Boolean = false
}
diff --git a/src/reflect/scala/reflect/macros/Enclosures.scala b/src/reflect/scala/reflect/macros/Enclosures.scala
index a4ad71c348..69ede42cc7 100644
--- a/src/reflect/scala/reflect/macros/Enclosures.scala
+++ b/src/reflect/scala/reflect/macros/Enclosures.scala
@@ -1,66 +1,114 @@
-package scala.reflect
+package scala
+package reflect
package macros
+import scala.language.existentials // SI-6541
+
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that exposes
- * enclosing trees (method, class, compilation unit and currently compiled application),
+ * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that exposes
+ * enclosing trees (method, class, compilation unit and currently compiled macro application),
* the enclosing position of the macro expansion, as well as macros and implicits
* that are currently in-flight.
+ *
+ * Starting from Scala 2.11.0, the APIs to get the trees enclosing by the current macro application are deprecated,
+ * and the reasons for that are two-fold. Firstly, we would like to move towards the philosophy of locally-expanded macros,
+ * as it has proven to be important for understanding of code. Secondly, within the current architecture of scalac,
+ * we are unable to have c.enclosingTree-style APIs working robustly. Required changes to the typechecker would greatly
+ * exceed the effort that we would like to expend on this feature given the existence of more pressing concerns at the moment.
+ * This is somewhat aligned with the overall evolution of macros during the 2.11 development cycle, where we played with
+ * `c.introduceTopLevel` and `c.introduceMember`, but at the end of the day decided to reject them.
+ *
+ * If you're relying on the now deprecated APIs, consider using the new [[c.internal.enclosingOwner]] method that can be used to obtain
+ * the names of enclosing definitions. Alternatively try reformulating your macros in terms of completely local expansion
+ * and/or joining a discussion of a somewhat related potential language feature at [[https://groups.google.com/forum/#!topic/scala-debate/f4CLmYShX6Q]].
+ * We also welcome questions and suggestions on our mailing lists, where we would be happy to further discuss this matter.
*/
trait Enclosures {
- self: Context =>
+ self: blackbox.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
+ def 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.
+ * 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]
-
- /** Information about one of the currently considered implicit candidates.
- * Candidates are used in plural form, because implicit parameters may themselves have implicit parameters,
- * hence implicit searches can recursively trigger other implicit searches.
- *
- * Can be useful to get information about an application with an implicit parameter that is materialized during current macro expansion.
- * If we're in an implicit macro being expanded, it's included in this list.
- *
- * 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)]
+ def enclosingMacros: List[blackbox.Context]
/** Tries to guess a position for the enclosing application.
- * But that is simple, right? Just dereference ``pos'' of ``macroApplication''? Not really.
+ * 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.
+ * Surprisingly, quite often we can do this by navigation the `enclosingMacros` stack.
*/
- val enclosingPosition: Position
+ def enclosingPosition: Position
/** Tree that corresponds to the enclosing method, or EmptyTree if not applicable.
+ * @see [[scala.reflect.macros.Enclosures]]
*/
- val enclosingMethod: Tree
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
+ def enclosingMethod: Tree
/** Tree that corresponds to the enclosing class, or EmptyTree if not applicable.
+ * @see [[scala.reflect.macros.Enclosures]]
+ */
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
+ def enclosingClass: Tree
+
+ /** Tree that corresponds to the enclosing DefDef tree.
+ * Throws `EnclosureException` if there's no such enclosing tree.
+ * @see [[scala.reflect.macros.Enclosures]]
+ */
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
+ def enclosingDef: universe.DefDef
+
+ /** Tree that corresponds to the enclosing Template tree.
+ * Throws `EnclosureException` if there's no such enclosing tree.
+ * @see [[scala.reflect.macros.Enclosures]]
+ */
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
+ def enclosingTemplate: universe.Template
+
+ /** Tree that corresponds to the enclosing ImplDef tree (i.e. either ClassDef or ModuleDef).
+ * Throws `EnclosureException` if there's no such enclosing tree.
+ * @see [[scala.reflect.macros.Enclosures]]
*/
- val enclosingClass: Tree
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
+ def enclosingImpl: universe.ImplDef
+
+ /** Tree that corresponds to the enclosing PackageDef tree.
+ * Throws `EnclosureException` if there's no such enclosing tree.
+ * @see [[scala.reflect.macros.Enclosures]]
+ */
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
+ def enclosingPackage: universe.PackageDef
/** Compilation unit that contains this macro application.
+ * @see [[scala.reflect.macros.Enclosures]]
*/
- val enclosingUnit: CompilationUnit
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
+ def enclosingUnit: CompilationUnit
/** Compilation run that contains this macro application.
+ * @see [[scala.reflect.macros.Enclosures]]
+ */
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
+ def enclosingRun: Run
+
+ /** Indicates than one of the enclosure methods failed to find a tree
+ * of required type among enclosing trees.
+ * @see [[scala.reflect.macros.Enclosures]]
*/
- val enclosingRun: Run
-} \ No newline at end of file
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
+ case class EnclosureException(expected: Class[_], enclosingTrees: List[Tree])
+ extends Exception(s"Couldn't find a tree of type $expected among enclosing trees $enclosingTrees")
+}
diff --git a/src/reflect/scala/reflect/macros/Evals.scala b/src/reflect/scala/reflect/macros/Evals.scala
index 37680c219b..68e07dd319 100644
--- a/src/reflect/scala/reflect/macros/Evals.scala
+++ b/src/reflect/scala/reflect/macros/Evals.scala
@@ -1,14 +1,15 @@
-package scala.reflect
+package scala
+package reflect
package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that provides
+ * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that provides
* a facility to evaluate trees.
*/
trait Evals {
- self: Context =>
+ self: blackbox.Context =>
/** Takes a typed wrapper for a tree of type `T` and evaluates it to a value of type `T`.
*
@@ -16,13 +17,13 @@ trait Evals {
* permitted by the shape of the arguments.
*
* Known issues: because of [[https://issues.scala-lang.org/browse/SI-5748 https://issues.scala-lang.org/browse/SI-5748]]
- * trees being evaluated first need to undergo `resetAllAttrs`. Resetting symbols and types
+ * trees being evaluated first need to undergo `untypecheck`. Resetting symbols and types
* mutates the tree in place, therefore the conventional approach is to `duplicate` the tree first.
*
* {{{
* scala> def impl(c: Context)(x: c.Expr[String]) = {
- * | val x1 = c.Expr[String](c.resetAllAttrs(x.tree.duplicate))
- * | println(s"compile-time value is: \${c.eval(x1)}")
+ * | val x1 = c.Expr[String](c.untypecheck(x.tree.duplicate))
+ * | println(s"compile-time value is: ${c.eval(x1)}")
* | x
* | }
* impl: (c: Context)(x: c.Expr[String])c.Expr[String]
@@ -54,4 +55,4 @@ trait Evals {
* refers to a runtime value `x`, which is unknown at compile time.
*/
def eval[T](expr: Expr[T]): T
-} \ No newline at end of file
+}
diff --git a/src/reflect/scala/reflect/macros/ExprUtils.scala b/src/reflect/scala/reflect/macros/ExprUtils.scala
index 458cde9692..c438653c92 100644
--- a/src/reflect/scala/reflect/macros/ExprUtils.scala
+++ b/src/reflect/scala/reflect/macros/ExprUtils.scala
@@ -1,51 +1,65 @@
-package scala.reflect
+package scala
+package reflect
package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that defines shorthands for the
+ * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that defines shorthands for the
* most common `Expr`-creating functions.
*/
trait ExprUtils {
- self: Context =>
+ self: blackbox.Context =>
/** Shorthand for `Literal(Constant(null))` in the underlying `universe`. */
+ @deprecated("Use quasiquotes instead", "2.11.0")
def literalNull: Expr[Null]
/** Shorthand for `Literal(Constant(()))` in the underlying `universe`. */
+ @deprecated("Use quasiquotes instead", "2.11.0")
def literalUnit: Expr[Unit]
/** Shorthand for `Literal(Constant(true))` in the underlying `universe`. */
+ @deprecated("Use quasiquotes instead", "2.11.0")
def literalTrue: Expr[Boolean]
/** Shorthand for `Literal(Constant(false))` in the underlying `universe`. */
+ @deprecated("Use quasiquotes instead", "2.11.0")
def literalFalse: Expr[Boolean]
/** Shorthand for `Literal(Constant(x: Boolean))` in the underlying `universe`. */
+ @deprecated("Use quasiquotes instead", "2.11.0")
def literal(x: Boolean): Expr[Boolean]
/** Shorthand for `Literal(Constant(x: Byte))` in the underlying `universe`. */
+ @deprecated("Use quasiquotes instead", "2.11.0")
def literal(x: Byte): Expr[Byte]
/** Shorthand for `Literal(Constant(x: Short))` in the underlying `universe`. */
+ @deprecated("Use quasiquotes instead", "2.11.0")
def literal(x: Short): Expr[Short]
/** Shorthand for `Literal(Constant(x: Int))` in the underlying `universe`. */
+ @deprecated("Use quasiquotes instead", "2.11.0")
def literal(x: Int): Expr[Int]
/** Shorthand for `Literal(Constant(x: Long))` in the underlying `universe`. */
+ @deprecated("Use quasiquotes instead", "2.11.0")
def literal(x: Long): Expr[Long]
/** Shorthand for `Literal(Constant(x: Float))` in the underlying `universe`. */
+ @deprecated("Use quasiquotes instead", "2.11.0")
def literal(x: Float): Expr[Float]
/** Shorthand for `Literal(Constant(x: Double))` in the underlying `universe`. */
+ @deprecated("Use quasiquotes instead", "2.11.0")
def literal(x: Double): Expr[Double]
/** Shorthand for `Literal(Constant(x: String))` in the underlying `universe`. */
+ @deprecated("Use quasiquotes instead", "2.11.0")
def literal(x: String): Expr[String]
/** Shorthand for `Literal(Constant(x: Char))` in the underlying `universe`. */
+ @deprecated("Use quasiquotes instead", "2.11.0")
def literal(x: Char): Expr[Char]
}
diff --git a/src/reflect/scala/reflect/macros/FrontEnds.scala b/src/reflect/scala/reflect/macros/FrontEnds.scala
index 67b24088b5..a770f325b2 100644
--- a/src/reflect/scala/reflect/macros/FrontEnds.scala
+++ b/src/reflect/scala/reflect/macros/FrontEnds.scala
@@ -1,15 +1,16 @@
-package scala.reflect
+package scala
+package reflect
package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that
+ * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that
* provides facilities to communicate with the compiler's front end
* (emit warnings, errors and other sorts of messages).
*/
trait FrontEnds {
- self: Context =>
+ self: blackbox.Context =>
/** For sending a message which should not be labeled as a warning/error,
* but also shouldn't require -verbose to be visible.
@@ -44,4 +45,4 @@ trait FrontEnds {
* Use `enclosingPosition` if you're in doubt what position to pass to `pos`.
*/
def abort(pos: Position, msg: String): Nothing
-} \ No newline at end of file
+}
diff --git a/src/reflect/scala/reflect/macros/Infrastructure.scala b/src/reflect/scala/reflect/macros/Infrastructure.scala
index 99706e84fe..0f2d9ce4cf 100644
--- a/src/reflect/scala/reflect/macros/Infrastructure.scala
+++ b/src/reflect/scala/reflect/macros/Infrastructure.scala
@@ -1,14 +1,15 @@
-package scala.reflect
+package scala
+package reflect
package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that
+ * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that
* provides facilities to communicate with the compiler's infrastructure.
*/
trait Infrastructure {
- self: Context =>
+ self: blackbox.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.
@@ -22,4 +23,4 @@ trait Infrastructure {
/** Exposes current classpath. */
def classPath: List[java.net.URL]
-} \ No newline at end of file
+}
diff --git a/src/reflect/scala/reflect/macros/Internals.scala b/src/reflect/scala/reflect/macros/Internals.scala
new file mode 100644
index 0000000000..75164344da
--- /dev/null
+++ b/src/reflect/scala/reflect/macros/Internals.scala
@@ -0,0 +1,79 @@
+package scala
+package reflect
+package macros
+
+/**
+ * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
+ * @see [[scala.reflect.api.Internals]]
+ */
+trait Internals {
+ self: blackbox.Context =>
+
+ /** @see [[scala.reflect.api.Internals]] */
+ val internal: ContextInternalApi
+
+ /** @see [[scala.reflect.api.Internals]] */
+ trait ContextInternalApi extends universe.MacroInternalApi {
+ /** Symbol associated with the innermost enclosing lexical context.
+ * Walking the owner chain of this symbol will reveal information about more and more enclosing contexts.
+ */
+ def enclosingOwner: Symbol
+
+ /** Functions that are available during [[transform]].
+ * @see [[transform]]
+ */
+ trait TransformApi {
+ /** Calls the current transformer on the given tree.
+ * Current transformer = argument to the `transform` call.
+ */
+ def recur(tree: Tree): Tree
+
+ /** Calls the default transformer on the given tree.
+ * Default transformer = recur into tree's children and assemble the results.
+ */
+ def default(tree: Tree): Tree
+ }
+
+ /** Transforms a given tree using the provided function.
+ * @see [[TransformApi]]
+ */
+ // TODO: explore a more concise notation that Denys and I discussed today
+ // when transformer is PartialFunction[Tree, Tree]] and TransformApi is passed magically
+ // also cf. https://github.com/dsl-paradise/dsl-paradise
+ def transform(tree: Tree)(transformer: (Tree, TransformApi) => Tree): Tree
+
+ /** Functions that are available during [[typingTransform]].
+ * @see [[typingTransform]]
+ */
+ trait TypingTransformApi extends TransformApi {
+ /** Temporarily pushes the given symbol onto the owner stack, creating a new local typer,
+ * invoke the given operation and then rollback the changes to the owner stack.
+ */
+ def atOwner[T](owner: Symbol)(op: => T): T
+
+ /** Temporarily pushes the given tree onto the recursion stack, and then calls `atOwner(symbol)(trans)`.
+ */
+ def atOwner[T](tree: Tree, owner: Symbol)(op: => T): T
+
+ /** Returns the symbol currently on the top of the owner stack.
+ * If we're not inside any `atOwner` call, then macro application's context owner will be used.
+ */
+ def currentOwner: Symbol
+
+ /** Typechecks the given tree using the local typer currently on the top of the owner stack.
+ * If we're not inside any `atOwner` call, then macro application's callsite typer will be used.
+ */
+ def typecheck(tree: Tree): Tree
+ }
+
+ /** Transforms a given tree using the provided function.
+ * @see [[TypingTransformApi]]
+ */
+ def typingTransform(tree: Tree)(transformer: (Tree, TypingTransformApi) => Tree): Tree
+
+ /** Transforms a given tree at a given owner using the provided function.
+ * @see [[TypingTransformApi]]
+ */
+ def typingTransform(tree: Tree, owner: Symbol)(transformer: (Tree, TypingTransformApi) => Tree): Tree
+ }
+}
diff --git a/src/reflect/scala/reflect/macros/Names.scala b/src/reflect/scala/reflect/macros/Names.scala
index 8bbaa5f848..4f3448e1ed 100644
--- a/src/reflect/scala/reflect/macros/Names.scala
+++ b/src/reflect/scala/reflect/macros/Names.scala
@@ -1,23 +1,56 @@
-package scala.reflect
+package scala
+package reflect
package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that
- * provides functions that generate unique names.
+ * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that
+ * provides functions that generate fresh names.
+ *
+ * In the current implementation, fresh names are more or less unique in the sense that
+ * within the same compilation run they are guaranteed not to clash with:
+ * 1) Results of past and future invocations of functions of `freshName` family
+ * 2) User-defined or macro-generated names that don't contain dollar symbols
+ * 3) Macro-generated names that are created by concatenating names from the first, second and third categories
+ *
+ * Uniqueness of fresh names across compilation runs is not guaranteed, but that's something
+ * that we would like to improve upon in future releases. See [[https://issues.scala-lang.org/browse/SI-6879]] for more information.
+ *
+ * @define freshNameNoParams
+ * Creates a string that represents a more or less unique name.
+ * Consult [[scala.reflect.macros.Names]] for more information on uniqueness of such names.
+ *
+ * @define freshNameStringParam
+ * Creates a string that represents a more or less unique name having a given prefix.
+ * Consult [[scala.reflect.macros.Names]] for more information on uniqueness of such names.
+ *
+ * @define freshNameNameParam
+ * Creates a more or less unique name having a given name as a prefix and
+ * having the same flavor (term name or type name) as the given name.
+ * Consult [[scala.reflect.macros.Names]] for more information on uniqueness of such names.
*/
trait Names {
- self: Context =>
+ self: blackbox.Context =>
- /** Creates a unique string. */
+ /** $freshNameNoParams */
+ @deprecated("Use freshName instead", "2.11.0")
def fresh(): String
- /** Creates a unique string having a given prefix. */
+ /** $freshNameStringParam */
+ @deprecated("Use freshName instead", "2.11.0")
def fresh(name: String): String
- /** Creates a unique name having a given name as a prefix and
- * having the same flavor (term name or type name) as the given name.
- */
+ /** $freshNameNameParam */
+ @deprecated("Use freshName instead", "2.11.0")
def fresh[NameType <: Name](name: NameType): NameType
+
+ /** $freshNameNoParams */
+ def freshName(): String
+
+ /** $freshNameStringParam */
+ def freshName(name: String): String
+
+ /** $freshNameNameParam */
+ def freshName[NameType <: Name](name: NameType): NameType
}
diff --git a/src/reflect/scala/reflect/macros/Parsers.scala b/src/reflect/scala/reflect/macros/Parsers.scala
index 93a763792c..720b754649 100644
--- a/src/reflect/scala/reflect/macros/Parsers.scala
+++ b/src/reflect/scala/reflect/macros/Parsers.scala
@@ -1,14 +1,15 @@
-package scala.reflect
+package scala
+package reflect
package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that
+ * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that
* exposes functions to parse strings with Scala code into trees.
*/
trait Parsers {
- self: Context =>
+ self: blackbox.Context =>
/** Parses a string with a Scala expression into an abstract syntax tree.
* Only works for expressions, i.e. parsing a package declaration will fail.
@@ -19,4 +20,4 @@ trait Parsers {
/** Indicates an error during [[scala.reflect.macros.Parsers#parse]].
*/
-case class ParseException(val pos: scala.reflect.api.Position, val msg: String) extends Exception(msg)
+case class ParseException(pos: scala.reflect.api.Position, msg: String) extends Exception(msg)
diff --git a/src/reflect/scala/reflect/macros/Reifiers.scala b/src/reflect/scala/reflect/macros/Reifiers.scala
index 3db7b9af02..e35a5c8622 100644
--- a/src/reflect/scala/reflect/macros/Reifiers.scala
+++ b/src/reflect/scala/reflect/macros/Reifiers.scala
@@ -1,26 +1,27 @@
-package scala.reflect
+package scala
+package reflect
package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that
+ * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that
* exposes functions to save reflection artifacts for runtime.
*/
trait Reifiers {
- self: Context =>
+ self: blackbox.Context =>
/** 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''.
+ * 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 ``universe.treeBuild.mkRuntimeUniverseRef''.
- * Possible values for ``mirror'' include ``EmptyTree'' (in that case the reifier will automatically pick an appropriate mirror).
+ * The produced tree will be bound to the specified `universe` and `mirror`.
+ * Possible values for `universe` include `universe.internal.gen.mkRuntimeUniverseRef`.
+ * 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).
+ * 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:
+ * 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.
@@ -39,7 +40,7 @@ trait Reifiers {
* * 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.
+ * * 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
@@ -48,13 +49,13 @@ trait Reifiers {
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''.
+ * 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).
+ * 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
@@ -86,10 +87,10 @@ trait Reifiers {
* Such errors represent one of the standard ways for reification to go wrong, e.g.
* an attempt to create a `TypeTag` from a weak type.
*/
-case class ReificationException(val pos: scala.reflect.api.Position, val msg: String) extends Exception(msg)
+case class ReificationException(pos: scala.reflect.api.Position, msg: String) extends Exception(msg)
/** Indicates an unexpected expected error during one of the `reifyXXX` methods in [[scala.reflect.macros.Reifiers]].
* Such errors wrap random crashes in reification logic and are distinguished from expected [[scala.reflect.macros.ReificationException]]s
* so that the latter can be reported as compilation errors, while the former manifest themselves as compiler crashes.
*/
-case class UnexpectedReificationException(val pos: scala.reflect.api.Position, val msg: String, val cause: Throwable = null) extends Exception(msg, cause)
+case class UnexpectedReificationException(pos: scala.reflect.api.Position, msg: String, cause: Throwable = null) extends Exception(msg, cause)
diff --git a/src/reflect/scala/reflect/macros/TreeBuilder.scala b/src/reflect/scala/reflect/macros/TreeBuilder.scala
deleted file mode 100644
index 204dc40858..0000000000
--- a/src/reflect/scala/reflect/macros/TreeBuilder.scala
+++ /dev/null
@@ -1,72 +0,0 @@
-package scala.reflect
-package macros
-
-/**
- * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
- *
- * A helper available in [[scala.reflect.macros.Universe]] that defines shorthands for the
- * most common tree-creating functions.
- */
-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
-
- /** A tree that refers to the runtime reflexive universe, ``scala.reflect.runtime.universe''. */
- def mkRuntimeUniverseRef: Tree
-}
diff --git a/src/reflect/scala/reflect/macros/Typers.scala b/src/reflect/scala/reflect/macros/Typers.scala
index d36636a6d2..d0dccb469d 100644
--- a/src/reflect/scala/reflect/macros/Typers.scala
+++ b/src/reflect/scala/reflect/macros/Typers.scala
@@ -1,16 +1,17 @@
-package scala.reflect
+package scala
+package reflect
package macros
+import scala.reflect.internal.{Mode => InternalMode}
+
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that
+ * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that
* partially exposes the type checker to macro writers.
*/
trait Typers {
- self: Context =>
-
- import universe._
+ self: blackbox.Context =>
/** 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.
@@ -22,21 +23,45 @@ trait Typers {
* 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]
+ def openMacros: List[blackbox.Context]
- /** Information about one of the currently considered implicit candidates.
- * Candidates are used in plural form, because implicit parameters may themselves have implicit parameters,
- * hence implicit searches can recursively trigger other implicit searches.
- *
- * Can be useful to get information about an application with an implicit parameter that is materialized during current macro expansion.
- * If we're in an implicit macro being expanded, it's included in this list.
- *
- * 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.
+ /** Represents mode of operations of the typechecker underlying `c.typecheck` calls.
+ * Is necessary since the shape of the typechecked tree alone is not enough to guess how it should be typechecked.
+ * Can be EXPRmode (typecheck as a term), TYPEmode (typecheck as a type) or PATTERNmode (typecheck as a pattern).
+ */
+ // I'd very much like to make use of https://github.com/dsl-paradise/dsl-paradise here!
+ type TypecheckMode
+
+ /** Indicates that an argument to `c.typecheck` should be typechecked as a term.
+ * This is the default typechecking mode in Scala 2.11 and the only one supported in Scala 2.10.
+ */
+ val TERMmode: TypecheckMode
+
+ /** Indicates that an argument to `c.typecheck` should be typechecked as a type.
+ */
+ val TYPEmode: TypecheckMode
+
+ /** Indicates that an argument to `c.typecheck` should be typechecked as a pattern.
+ */
+ val PATTERNmode: TypecheckMode
+
+ /** @see `scala.reflect.macros.TypecheckException`
+ */
+ type TypecheckException = scala.reflect.macros.TypecheckException
+
+ /** @see `scala.reflect.macros.TypecheckException`
*/
- def openImplicits: List[(Type, Tree)]
+ val TypecheckException = scala.reflect.macros.TypecheckException
- /** Typechecks the provided tree against the expected type `pt` in the macro callsite context.
+ /** @see `Typers.typecheck`
+ */
+ @deprecated("Use `c.typecheck` instead", "2.11.0")
+ def typeCheck(tree: Tree, pt: Type = universe.WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree =
+ typecheck(tree, TERMmode, pt, silent, withImplicitViewsDisabled, withMacrosDisabled)
+
+ /** Typechecks the provided tree against the expected type `pt` in the macro callsite context
+ * under typechecking mode specified in `mode` with [[EXPRmode]] being default.
+ * This populates symbols and types of the tree and possibly transforms it to reflect certain desugarings.
*
* If `silent` is false, `TypecheckException` 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.
@@ -49,7 +74,7 @@ trait Typers {
*
* @throws [[scala.reflect.macros.TypecheckException]]
*/
- def typeCheck(tree: Tree, pt: Type = WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree
+ def typecheck(tree: Tree, mode: TypecheckMode = TERMmode, pt: Type = universe.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.
@@ -57,7 +82,7 @@ trait Typers {
* If `silent` is false, `TypecheckException` 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.
+ * Unlike in `typecheck`, `silent` is true by default.
*
* @throws [[scala.reflect.macros.TypecheckException]]
*/
@@ -69,27 +94,35 @@ trait Typers {
* If `silent` is false, `TypecheckException` 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.
+ * Unlike in `typecheck`, `silent` is true by default.
*
* @throws [[scala.reflect.macros.TypecheckException]]
*/
def inferImplicitView(tree: Tree, from: Type, to: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, 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.
+ /** Recursively resets locally defined symbols and types in a given tree.
+ * WARNING: Don't use this API, go for [[untypecheck]] instead.
*/
- def resetAllAttrs(tree: Tree): Tree
+ @deprecated("Use `c.untypecheck` instead", "2.11.0")
+ def resetLocalAttrs(tree: Tree): Tree
- /** Recursively resets locally defined symbols and types in a given tree.
+ /** In the current implementation of Scala's reflection API, untyped trees (also known as parser trees or unattributed trees)
+ * are observationally different from typed trees (also known as typer trees, typechecked trees or attributed trees),
*
- * 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.
+ * Usually, if some compiler API takes a tree, then both untyped and typed trees will do. However in some cases,
+ * only untyped or only typed trees are appropriate. For example, [[eval]] only accepts untyped trees and one can only splice
+ * typed trees inside typed trees. Therefore in the current reflection API, there is a need in functions
+ * that go back and forth between untyped and typed trees. For this we have [[typecheck]] and `untypecheck`.
+ *
+ * Note that `untypecheck` is currently afflicted by https://issues.scala-lang.org/browse/SI-5464,
+ * which makes it sometimes corrupt trees so that they don't make sense anymore. Unfortunately, there's no workaround for that.
+ * We plan to fix this issue soon, but for now please keep it in mind.
+ *
+ * @see [[http://stackoverflow.com/questions/20936509/scala-macros-what-is-the-difference-between-typed-aka-typechecked-an-untyped]]
*/
- def resetLocalAttrs(tree: Tree): Tree
+ def untypecheck(tree: Tree): Tree
}
/** Indicates an error during one of the methods in [[scala.reflect.macros.Typers]].
*/
-case class TypecheckException(val pos: scala.reflect.api.Position, val msg: String) extends Exception(msg)
+case class TypecheckException(pos: scala.reflect.api.Position, msg: String) extends Exception(msg)
diff --git a/src/reflect/scala/reflect/macros/Universe.scala b/src/reflect/scala/reflect/macros/Universe.scala
index 4e76f7c408..1eb67215bb 100644
--- a/src/reflect/scala/reflect/macros/Universe.scala
+++ b/src/reflect/scala/reflect/macros/Universe.scala
@@ -1,6 +1,10 @@
-package scala.reflect
+package scala
+package reflect
package macros
+import scala.language.implicitConversions
+import scala.language.higherKinds
+
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
@@ -16,111 +20,96 @@ package macros
*/
abstract class Universe extends scala.reflect.api.Universe {
- /** A factory that encapsulates common tree-building functions.
- * @group Macros
- */
- val treeBuild: TreeBuilder { val global: Universe.this.type }
+ /** @inheritdoc */
+ override type Internal <: MacroInternalApi
- /** The API of reflection artifacts that support [[scala.reflect.macros.Attachments]].
- * These artifacts are trees and symbols.
- * @group Macros
- */
- trait AttachableApi {
- /** The attachment of the reflection artifact. */
- def attachments: Attachments { type Pos = Position }
+ /** @inheritdoc */
+ trait MacroInternalApi extends InternalApi { internal =>
- /** Updates the attachment with the payload slot of T added/updated with the provided value.
- * Replaces an existing payload of the same type, if exists.
- * Returns the reflection artifact itself.
+ /** Adds a given symbol to the given scope.
*/
- def updateAttachment[T: ClassTag](attachment: T): AttachableApi.this.type
+ def enter(scope: Scope, sym: Symbol): scope.type
- /** Update the attachment with the payload of the given class type `T` removed.
- * Returns the reflection artifact itself.
+ /** Removes a given symbol to the given scope.
*/
- def removeAttachment[T: ClassTag]: AttachableApi.this.type
- }
+ def unlink(scope: Scope, sym: Symbol): scope.type
- // Symbol extensions ---------------------------------------------------------------
+ /** Collects all the symbols defined by subtrees of `tree` that are owned by `prev`,
+ * and then changes their owner to point to `next`.
+ *
+ * This is an essential tool to battle owner chain corruption when moving trees
+ * from one lexical context to another. Whenever you take an attributed tree that
+ * has been typechecked under the Context owned by some symbol (let's call it `x`)
+ * and splice it elsewhere, into the Context owned by another symbol (let's call it `y`),
+ * it is imperative that you either call `untypecheck` or do `changeOwner(tree, x, y)`.
+ *
+ * Since at the moment `untypecheck` has fundamental problem that can sometimes lead to tree corruption,
+ * `changeOwner` becomes an indispensible tool in building 100% robust macros.
+ * Future versions of the reflection API might obviate the need in taking care of
+ * these low-level details, but at the moment this is what we've got.
+ */
+ def changeOwner(tree: Tree, prev: Symbol, next: Symbol): tree.type
- /** The `Symbol` API is extended for macros: See [[SymbolContextApi]] for details.
- *
- * @group Macros
- */
- override type Symbol >: Null <: SymbolContextApi
+ /** Advanced tree factories */
+ val gen: TreeGen
- /** The extended API of symbols that's supported in macro context universes
- * @group API
- */
- trait SymbolContextApi extends SymbolApi with AttachableApi { self: Symbol =>
+ /** The attachment of the symbol. */
+ def attachments(symbol: Symbol): Attachments { type Pos = Position }
- /** If this symbol is a skolem, its corresponding type parameter, otherwise the symbol itself.
- *
- * [[https://groups.google.com/forum/#!msg/scala-internals/0j8laVNTQsI/kRXMF_c8bGsJ To quote Martin Odersky]],
- * skolems are synthetic type "constants" that are copies of existentially bound or universally
- * bound type variables. E.g. if one is inside the right-hand side of a method:
- *
- * {{{
- * def foo[T](x: T) = ... foo[List[T]]....
- * }}}
- *
- * the skolem named `T` refers to the unknown type instance of `T` when `foo` is called. It needs to be different
- * from the type parameter because in a recursive call as in the `foo[List[T]]` above the type parameter gets
- * substituted with `List[T]`, but the ''type skolem'' stays what it is.
- *
- * The other form of skolem is an ''existential skolem''. Say one has a function
- *
- * {{{
- * def bar(xs: List[T] forSome { type T }) = xs.head
- * }}}
- *
- * then each occurrence of `xs` on the right will have type `List[T']` where `T'` is a fresh copy of `T`.
+ /** Updates the attachment with the payload slot of T added/updated with the provided value.
+ * Replaces an existing payload of the same type, if exists.
+ * Returns the symbol itself.
*/
- def deSkolemize: Symbol
+ def updateAttachment[T: ClassTag](symbol: Symbol, attachment: T): symbol.type
- /** The position of this symbol. */
- def pos: Position
+ /** Update the attachment with the payload of the given class type `T` removed.
+ * Returns the symbol itself.
+ */
+ def removeAttachment[T: ClassTag](symbol: Symbol): symbol.type
+
+ /** Sets the `owner` of the symbol. */
+ def setOwner(symbol: Symbol, newowner: Symbol): symbol.type
- /** Sets the `typeSignature` of the symbol. */
- def setTypeSignature(tpe: Type): Symbol
+ /** Sets the `info` of the symbol. */
+ def setInfo(symbol: Symbol, tpe: Type): symbol.type
/** Sets the `annotations` of the symbol. */
- def setAnnotations(annots: Annotation*): Symbol
+ def setAnnotations(symbol: Symbol, annots: Annotation*): symbol.type
/** Sets the `name` of the symbol. */
- def setName(name: Name): Symbol
+ def setName(symbol: Symbol, name: Name): symbol.type
/** Sets the `privateWithin` of the symbol. */
- def setPrivateWithin(sym: Symbol): Symbol
- }
+ def setPrivateWithin(symbol: Symbol, sym: Symbol): symbol.type
- // Tree extensions ---------------------------------------------------------------
+ /** Enables `flags` on the symbol. */
+ def setFlag(symbol: Symbol, flags: FlagSet): symbol.type
- /** The `Tree` API is extended for macros: See [[TreeContextApi]] for details.
- *
- * @group Macros
- */
- override type Tree >: Null <: TreeContextApi
+ /** Disables `flags` on the symbol. */
+ def resetFlag(symbol: Symbol, flags: FlagSet): symbol.type
- /** The extended API of trees that's supported in macro context universes
- * @group API
- */
- trait TreeContextApi extends TreeApi with AttachableApi { self: Tree =>
+ /** The attachment of the tree. */
+ def attachments(tree: Tree): Attachments { type Pos = Position }
- /** Sets the `pos` of the tree. Returns `Unit`. */
- def pos_=(pos: Position): Unit
+ /** Updates the attachment with the payload slot of T added/updated with the provided value.
+ * Replaces an existing payload of the same type, if exists.
+ * Returns the tree itself.
+ */
+ def updateAttachment[T: ClassTag](tree: Tree, attachment: T): tree.type
- /** Sets the `pos` of the tree. Returns the tree itself. */
- def setPos(newpos: Position): Tree
+ /** Update the attachment with the payload of the given class type `T` removed.
+ * Returns the tree itself.
+ */
+ def removeAttachment[T: ClassTag](tree: Tree): tree.type
- /** Sets the `tpe` of the tree. Returns `Unit`. */
- def tpe_=(t: Type): Unit
+ /** Sets the `pos` of the tree. Returns the tree itself. */
+ def setPos(tree: Tree, newpos: Position): tree.type
/** Sets the `tpe` of the tree. Returns the tree itself. */
- def setType(tp: Type): Tree
+ def setType(tree: Tree, tp: Type): tree.type
/** Like `setType`, but if this is a previously empty TypeTree that
- * fact is remembered so that resetAllAttrs will snap back.
+ * fact is remembered so that `untypecheck` 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,
@@ -128,7 +117,8 @@ abstract class Universe extends scala.reflect.api.Universe {
* 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
+ * `untypecheck` (or `resetAttrs` in compiler parlance) 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
@@ -136,93 +126,355 @@ abstract class Universe extends scala.reflect.api.Universe {
* and therefore should be abandoned if the current line of type
* inquiry doesn't work out.
*/
- def defineType(tp: Type): Tree
-
- /** Sets the `symbol` of the tree. Returns `Unit`. */
- def symbol_=(sym: Symbol): Unit
+ def defineType(tree: Tree, tp: Type): tree.type
/** Sets the `symbol` of the tree. Returns the tree itself. */
- def setSymbol(sym: Symbol): Tree
- }
+ def setSymbol(tree: Tree, sym: Symbol): tree.type
- /** @inheritdoc */
- override type SymTree >: Null <: Tree with SymTreeContextApi
+ /** Sets the `original` field of the type tree. */
+ def setOriginal(tt: TypeTree, original: Tree): TypeTree
- /** The extended API of sym trees that's supported in macro context universes
- * @group API
- */
- trait SymTreeContextApi extends SymTreeApi { this: SymTree =>
- /** Sets the `symbol` field of the sym tree. */
- var symbol: Symbol
- }
+ /** Mark a variable as captured; i.e. force boxing in a *Ref type.
+ * @group Macros
+ */
+ def captureVariable(vble: Symbol): Unit
- /** @inheritdoc */
- override type TypeTree >: Null <: TypTree with TypeTreeContextApi
+ /** Mark given identifier as a reference to a captured variable itself
+ * suppressing dereferencing with the `elem` field.
+ * @group Macros
+ */
+ def referenceCapturedVariable(vble: Symbol): Tree
- /** The extended API of sym trees that's supported in macro context universes
- * @group API
- */
- trait TypeTreeContextApi extends TypeTreeApi { this: TypeTree =>
- /** Sets the `original` field of the type tree. */
- def setOriginal(tree: Tree): this.type
+ /** Convert type of a captured variable to *Ref type.
+ * @group Macros
+ */
+ def capturedVariableType(vble: Symbol): Type
+
+ /** Retrieves the untyped list of subpatterns attached to selector dummy of an UnApply node.
+ * Useful in writing quasiquoting macros that do pattern matching.
+ */
+ def subpatterns(tree: Tree): Option[List[Tree]]
+
+ /** @inheritdoc */
+ override type Decorators <: MacroDecoratorApi
+
+ /** @inheritdoc */
+ trait MacroDecoratorApi extends DecoratorApi {
+ /** Extension methods for scopes */
+ type ScopeDecorator[T <: Scope] <: MacroScopeDecoratorApi[T]
+
+ /** @see [[ScopeDecorator]] */
+ implicit def scopeDecorator[T <: Scope](tree: T): ScopeDecorator[T]
+
+ /** @see [[ScopeDecorator]] */
+ class MacroScopeDecoratorApi[T <: Scope](val scope: T) {
+ /** @see [[internal.enter]] */
+ def enter(sym: Symbol): T = internal.enter(scope, sym)
+
+ /** @see [[internal.unlink]] */
+ def unlink(sym: Symbol): T = internal.unlink(scope, sym)
+ }
+
+ /** @inheritdoc */
+ override type TreeDecorator[T <: Tree] <: MacroTreeDecoratorApi[T]
+
+ /** @see [[TreeDecorator]] */
+ class MacroTreeDecoratorApi[T <: Tree](override val tree: T) extends TreeDecoratorApi[T](tree) {
+ /** @see [[internal.changeOwner]] */
+ def changeOwner(prev: Symbol, next: Symbol): tree.type = internal.changeOwner(tree, prev, next)
+
+ /** @see [[internal.attachments]] */
+ def attachments: Attachments { type Pos = Position } = internal.attachments(tree)
+
+ /** @see [[internal.updateAttachment]] */
+ def updateAttachment[A: ClassTag](attachment: A): tree.type = internal.updateAttachment(tree, attachment)
+
+ /** @see [[internal.removeAttachment]] */
+ def removeAttachment[A: ClassTag]: T = internal.removeAttachment[A](tree)
+
+ /** @see [[internal.setPos]] */
+ def setPos(newpos: Position): T = internal.setPos(tree, newpos)
+
+ /** @see [[internal.setType]] */
+ def setType(tp: Type): T = internal.setType(tree, tp)
+
+ /** @see [[internal.defineType]] */
+ def defineType(tp: Type): T = internal.defineType(tree, tp)
+
+ /** @see [[internal.setSymbol]] */
+ def setSymbol(sym: Symbol): T = internal.setSymbol(tree, sym)
+ }
+
+ /** Extension methods for typetrees */
+ type TypeTreeDecorator[T <: TypeTree] <: MacroTypeTreeDecoratorApi[T]
+
+ /** @see [[TypeTreeDecorator]] */
+ implicit def typeTreeDecorator[T <: TypeTree](tt: T): TypeTreeDecorator[T]
+
+ /** @see [[TypeTreeDecorator]] */
+ class MacroTypeTreeDecoratorApi[T <: TypeTree](val tt: T) {
+ /** @see [[internal.setOriginal]] */
+ def setOriginal(tree: Tree): TypeTree = internal.setOriginal(tt, tree)
+ }
+
+ /** @inheritdoc */
+ override type SymbolDecorator[T <: Symbol] <: MacroSymbolDecoratorApi[T]
+
+ /** @see [[TreeDecorator]] */
+ class MacroSymbolDecoratorApi[T <: Symbol](override val symbol: T) extends SymbolDecoratorApi[T](symbol) {
+ /** @see [[internal.attachments]] */
+ def attachments: Attachments { type Pos = Position } = internal.attachments(symbol)
+
+ /** @see [[internal.updateAttachment]] */
+ def updateAttachment[A: ClassTag](attachment: A): T = internal.updateAttachment(symbol, attachment)
+
+ /** @see [[internal.removeAttachment]] */
+ def removeAttachment[A: ClassTag]: T = internal.removeAttachment[A](symbol)
+
+ /** @see [[internal.setOwner]] */
+ def setOwner(newowner: Symbol): T = internal.setOwner(symbol, newowner)
+
+ /** @see [[internal.setInfo]] */
+ def setInfo(tpe: Type): T = internal.setInfo(symbol, tpe)
+
+ /** @see [[internal.setAnnotations]] */
+ def setAnnotations(annots: Annotation*): T = internal.setAnnotations(symbol, annots: _*)
+
+ /** @see [[internal.setName]] */
+ def setName(name: Name): T = internal.setName(symbol, name)
+
+ /** @see [[internal.setPrivateWithin]] */
+ def setPrivateWithin(sym: Symbol): T = internal.setPrivateWithin(symbol, sym)
+
+ /** @see [[internal.setFlag]] */
+ def setFlag(flags: FlagSet): T = internal.setFlag(symbol, flags)
+
+ /** @see [[internal.setFlag]] */
+ def resetFlag(flags: FlagSet): T = internal.resetFlag(symbol, flags)
+ }
+ }
}
- /** @inheritdoc */
- override type Ident >: Null <: RefTree with IdentContextApi
+ /** @group Internal */
+ trait TreeGen {
+ /** 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
- /** The extended API of idents that's supported in macro context universes
- * @group API
- */
- trait IdentContextApi extends IdentApi { this: Ident =>
- /** Was this ident created from a backquoted identifier? */
- def isBackquoted: Boolean
+ /** 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): RefTree
+
+ /** Builds a typed reference to given symbol. */
+ def mkAttributedRef(sym: Symbol): RefTree
+
+ def stabilize(tree: Tree): Tree
+
+ def mkAttributedStableRef(pre: Type, sym: Symbol): Tree
+
+ def mkAttributedStableRef(sym: Symbol): Tree
+
+ /** Builds an untyped reference to given symbol. Requires the symbol to be static. */
+ def mkUnattributedRef(sym: Symbol): RefTree
+
+ /** Builds an untyped reference to symbol with given name. Requires the symbol to be static. */
+ def mkUnattributedRef(fullName: Name): RefTree
+
+ /** Builds a typed This reference to given symbol. */
+ def mkAttributedThis(sym: Symbol): This
+
+ /** Builds a typed Ident with an underlying symbol. */
+ def mkAttributedIdent(sym: Symbol): RefTree
+
+ /** Builds a typed Select with an underlying symbol. */
+ def mkAttributedSelect(qual: Tree, sym: Symbol): RefTree
+
+ /** 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
+
+ /** A tree that refers to the runtime reflexive universe, `scala.reflect.runtime.universe`. */
+ def mkRuntimeUniverseRef: Tree
+
+ def mkZero(tp: Type): Tree
+
+ def mkCast(tree: Tree, pt: Type): Tree
}
- /** Mark a variable as captured; i.e. force boxing in a *Ref type.
- * @group Macros
- */
- def captureVariable(vble: Symbol): Unit
+ /** @see [[internal.gen]] */
+ @deprecated("Use `internal.gen` instead", "2.11.0")
+ val treeBuild: TreeGen
- /** Mark given identifier as a reference to a captured variable itself
- * suppressing dereferencing with the `elem` field.
- * @group Macros
- */
- def referenceCapturedVariable(vble: Symbol): Tree
+ /** @inheritdoc */
+ type Compat <: MacroCompatApi
- /** Convert type of a captured variable to *Ref type.
- * @group Macros
+ /** @see [[compat]]
+ * @group Internal
*/
- def capturedVariableType(vble: Symbol): Type
+ trait MacroCompatApi extends CompatApi {
+ /** Scala 2.10 compatibility enrichments for Symbol. */
+ implicit class MacroCompatibleSymbol(symbol: Symbol) {
+ /** @see [[InternalMacroApi.attachments]] */
+ @deprecated("Use `internal.attachments` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def attachments: Attachments { type Pos = Position } = internal.attachments(symbol)
+
+ /** @see [[InternalMacroApi.updateAttachment]] */
+ @deprecated("Use `internal.updateAttachment` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def updateAttachment[T: ClassTag](attachment: T): Symbol = internal.updateAttachment[T](symbol, attachment)
+
+ /** @see [[InternalMacroApi.removeAttachment]] */
+ @deprecated("Use `internal.removeAttachment` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def removeAttachment[T: ClassTag]: Symbol = internal.removeAttachment[T](symbol)
+
+ /** @see [[InternalMacroApi.setInfo]] */
+ @deprecated("Use `internal.setInfo` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def setTypeSignature(tpe: Type): Symbol = internal.setInfo(symbol, tpe)
+
+ /** @see [[InternalMacroApi.setAnnotations]] */
+ @deprecated("Use `internal.setAnnotations` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def setAnnotations(annots: Annotation*): Symbol = internal.setAnnotations(symbol, annots: _*)
+
+ /** @see [[InternalMacroApi.setName]] */
+ @deprecated("Use `internal.setName` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def setName(name: Name): Symbol = internal.setName(symbol, name)
+
+ /** @see [[InternalMacroApi.setPrivateWithin]] */
+ @deprecated("Use `internal.setPrivateWithin` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def setPrivateWithin(sym: Symbol): Symbol = internal.setPrivateWithin(symbol, sym)
+ }
+
+ /** Scala 2.10 compatibility enrichments for TypeTree. */
+ implicit class MacroCompatibleTree(tree: Tree) {
+ /** @see [[InternalMacroApi.attachments]] */
+ @deprecated("Use `internal.attachments` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def attachments: Attachments { type Pos = Position } = internal.attachments(tree)
+
+ /** @see [[InternalMacroApi.updateAttachment]] */
+ @deprecated("Use `internal.updateAttachment` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def updateAttachment[T: ClassTag](attachment: T): Tree = internal.updateAttachment[T](tree, attachment)
+
+ /** @see [[InternalMacroApi.removeAttachment]] */
+ @deprecated("Use `internal.removeAttachment` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def removeAttachment[T: ClassTag]: Tree = internal.removeAttachment[T](tree)
+
+ /** @see [[InternalMacroApi.setPos]] */
+ @deprecated("Use `internal.setPos` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def pos_=(pos: Position): Unit = internal.setPos(tree, pos)
+
+ /** @see [[InternalMacroApi.setPos]] */
+ @deprecated("Use `internal.setPos` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def setPos(newpos: Position): Tree = internal.setPos(tree, newpos)
+
+ /** @see [[InternalMacroApi.setType]] */
+ @deprecated("Use `internal.setType` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def tpe_=(t: Type): Unit = internal.setType(tree, t)
+
+ /** @see [[InternalMacroApi.setType]] */
+ @deprecated("Use `internal.setType` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def setType(tp: Type): Tree = internal.setType(tree, tp)
+
+ /** @see [[InternalMacroApi.defineType]] */
+ @deprecated("Use `internal.defineType` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def defineType(tp: Type): Tree = internal.defineType(tree, tp)
+
+ /** @see [[InternalMacroApi.setSymbol]] */
+ @deprecated("Use `internal.setSymbol` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def symbol_=(sym: Symbol): Unit = internal.setSymbol(tree, sym)
+
+ /** @see [[InternalMacroApi.setSymbol]] */
+ @deprecated("Use `internal.setSymbol` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def setSymbol(sym: Symbol): Tree = internal.setSymbol(tree, sym)
+ }
+
+ /** Scala 2.10 compatibility enrichments for TypeTree. */
+ implicit class CompatibleTypeTree(tt: TypeTree) {
+ /** @see [[InternalMacroApi.setOriginal]] */
+ @deprecated("Use `internal.setOriginal` instead or import `internal.decorators._` for infix syntax", "2.11.0")
+ def setOriginal(tree: Tree): TypeTree = internal.setOriginal(tt, tree)
+ }
+
+ /** @see [[InternalMacroApi.captureVariable]] */
+ @deprecated("Use `internal.captureVariable` instead", "2.11.0")
+ def captureVariable(vble: Symbol): Unit = internal.captureVariable(vble)
+
+ /** @see [[InternalMacroApi.captureVariable]] */
+ @deprecated("Use `internal.referenceCapturedVariable` instead", "2.11.0")
+ def referenceCapturedVariable(vble: Symbol): Tree = internal.referenceCapturedVariable(vble)
+
+ /** @see [[InternalMacroApi.captureVariable]] */
+ @deprecated("Use `internal.capturedVariableType` instead", "2.11.0")
+ def capturedVariableType(vble: Symbol): Type = internal.capturedVariableType(vble)
+ }
/** The type of compilation runs.
+ * @see [[scala.reflect.macros.Enclosures]]
* @template
* @group Macros
*/
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
type Run <: RunContextApi
/** Compilation run uniquely identifies current invocation of the compiler
* (e.g. can be used to implement per-run caches for macros) and provides access to units of work
* of the invocation (currently processed unit of work and the list of all units).
+ * @see [[scala.reflect.macros.Enclosures]]
* @group API
*/
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
trait RunContextApi {
/** Currently processed unit of work (a real or a virtual file). */
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
def currentUnit: CompilationUnit
/** All units of work comprising this compilation run. */
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
def units: Iterator[CompilationUnit]
}
/** The type of compilation units.
+ * @see [[scala.reflect.macros.Enclosures]]
* @template
* @group Macros
*/
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
type CompilationUnit <: CompilationUnitContextApi
/** Compilation unit describes a unit of work of the compilation run.
* It provides such information as file name, textual representation of the unit and the underlying AST.
+ * @see [[scala.reflect.macros.Enclosures]]
* @group API
*/
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
trait CompilationUnitContextApi {
/** Source file corresponding to this compilation unit.
*
@@ -233,9 +485,11 @@ abstract class Universe extends scala.reflect.api.Universe {
* It should not be used unless you know what you are doing. In subsequent releases, this API will be refined
* and exposed as a part of scala.reflect.api.
*/
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
def source: scala.reflect.internal.util.SourceFile
/** The AST that corresponds to this compilation unit. */
+ @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0")
def body: Tree
}
-} \ No newline at end of file
+}
diff --git a/src/reflect/scala/reflect/macros/Context.scala b/src/reflect/scala/reflect/macros/blackbox/Context.scala
index aa1c1db227..2f9c512efa 100644
--- a/src/reflect/scala/reflect/macros/Context.scala
+++ b/src/reflect/scala/reflect/macros/blackbox/Context.scala
@@ -1,14 +1,12 @@
-package scala.reflect
+package scala
+package reflect
package 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.macros (and probably reside in scala-compiler.jar)
+package blackbox
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * The Scala macros context.
+ * The blackbox Scala macros context.
*
* See [[scala.reflect.macros.package the overview page]] for a description of how macros work. This documentation
* entry provides information on the API available to macro writers.
@@ -26,6 +24,14 @@ package macros
* Other than that, macro contexts provide facilities for typechecking, exploring the compiler's symbol table and
* enclosing trees and compilation units, evaluating trees, logging warnings/errors and much more.
* Refer to the documentation of top-level traits in this package to learn the details.
+ *
+ * If a macro def refers to a macro impl that uses `blackbox.Context`, then this macro def becomes a blackbox macro,
+ * which means that its expansion will be upcast to its return type, enforcing faithfullness of that macro to its
+ * type signature. Whitebox macros, i.e. the ones defined with `whitebox.Context`, aren't bound by this restriction,
+ * which enables a number of important use cases, but they are also going to enjoy less support than blackbox macros,
+ * so choose wisely. See the [[http://docs.scala-lang.org/overviews/macros.html Macros Guide]] for more information.
+ *
+ * @see `scala.reflect.macros.whitebox.Context`
*/
trait Context extends Aliases
with Enclosures
@@ -36,7 +42,8 @@ trait Context extends Aliases
with Typers
with Parsers
with Evals
- with ExprUtils {
+ with ExprUtils
+ with Internals {
/** The compile-time universe. */
val universe: Universe
@@ -51,7 +58,7 @@ trait Context extends Aliases
/** The prefix tree from which the macro is selected.
*
- * For a example, for a macro `filter` defined as an instance method on a collection `Coll`,
+ * For example, for a macro `filter` defined as an instance method on a collection `Coll`,
* `prefix` represents an equivalent of `this` for normal instance methods:
*
* {{{
diff --git a/src/reflect/scala/reflect/macros/package.scala b/src/reflect/scala/reflect/macros/package.scala
index 21d189bb25..cc7111d794 100644
--- a/src/reflect/scala/reflect/macros/package.scala
+++ b/src/reflect/scala/reflect/macros/package.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
@@ -6,10 +7,22 @@ package scala.reflect
* The base package for Scala macros.
*
* Macros are functions that are called by the compiler during compilation.
- * Within these functions the programmer has access to compiler APIs exposed in [[scala.reflect.macros.Context]].
+ * Within these functions the programmer has access to compiler APIs.
* For example, it is possible to generate, analyze and typecheck code.
*
* See the [[http://docs.scala-lang.org/overviews/macros.html Macros Guide]] on how to get started with Scala macros.
*/
package object macros {
+ /** The Scala macros context.
+ *
+ * In Scala 2.11, macros that were once the one are split into blackbox and whitebox macros,
+ * with the former being better supported and the latter being more powerful. You can read about
+ * the details of the split and the associated trade-offs in the [[http://docs.scala-lang.org/overviews/macros.html Macros Guide]].
+ *
+ * `scala.reflect.macros.Context` follows this tendency and turns into `scala.reflect.macros.blackbox.Context`
+ * and `scala.reflect.macros.whitebox.Context`. The original `Context` is left in place for compatibility reasons,
+ * but it is now deprecated, nudging the users to choose between blackbox and whitebox macros.
+ */
+ @deprecated("Use blackbox.Context or whitebox.Context instead", "2.11.0")
+ type Context = whitebox.Context
} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/macros/whitebox/Context.scala b/src/reflect/scala/reflect/macros/whitebox/Context.scala
new file mode 100644
index 0000000000..bd48df46cc
--- /dev/null
+++ b/src/reflect/scala/reflect/macros/whitebox/Context.scala
@@ -0,0 +1,77 @@
+package scala
+package reflect
+package macros
+package whitebox
+
+/**
+ * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
+ *
+ * The whitebox Scala macros context.
+ *
+ * See [[scala.reflect.macros.package the overview page]] for a description of how macros work. This documentation
+ * entry provides information on the API available to macro writers.
+ *
+ * A macro context wraps a compiler universe exposed in `universe` and having type [[scala.reflect.macros.Universe]].
+ * This type is a refinement over the generic reflection API provided in [[scala.reflect.api.Universe]]. The
+ * extended Universe provides mutability for reflection artifacts (e.g. macros can change types of compiler trees,
+ * add annotation to symbols representing definitions, etc) and exposes some internal compiler functionality
+ * such as `Symbol.deSkolemize` or `Tree.attachments`.
+ *
+ * Another fundamental part of a macro context is `macroApplication`, which provides access to the tree undergoing
+ * macro expansion. Parts of this tree can be found in arguments of the corresponding macro implementations and
+ * in `prefix`, but `macroApplication` gives the full picture.
+ *
+ * Other than that, macro contexts provide facilities for typechecking, exploring the compiler's symbol table and
+ * enclosing trees and compilation units, evaluating trees, logging warnings/errors and much more.
+ * Refer to the documentation of top-level traits in this package to learn the details.
+ *
+ * If a macro def refers to a macro impl that uses `whitebox.Context`, then this macro def becomes a whitebox macro,
+ * gaining the ability to refine the type of its expansion beyond its official return type, which enables a number of important use cases.
+ * Blackbox macros, i.e. the ones defined with `blackbox.Context`, can't do that, so they are less powerful.
+ * However blackbox macros are also going to enjoy better support than whitebox macros, so choose wisely.
+ * See the [[http://docs.scala-lang.org/overviews/macros.html Macros Guide]] for more information.
+ *
+ * @see `scala.reflect.macros.blackbox.Context`
+ */
+trait Context extends blackbox.Context {
+ /** @inheritdoc
+ */
+ def openMacros: List[Context]
+
+ /** @inheritdoc
+ */
+ def enclosingMacros: List[Context]
+
+ /** Information about one of the currently considered implicit candidates.
+ * Candidates are used in plural form, because implicit parameters may themselves have implicit parameters,
+ * hence implicit searches can recursively trigger other implicit searches.
+ *
+ * `pre` and `sym` provide information about the candidate itself.
+ * `pt` and `tree` store the parameters of the implicit search the candidate is participating in.
+ */
+ case class ImplicitCandidate(pre: Type, sym: Symbol, pt: Type, tree: Tree)
+
+ /** Information about one of the currently considered implicit candidates.
+ * Candidates are used in plural form, because implicit parameters may themselves have implicit parameters,
+ * hence implicit searches can recursively trigger other implicit searches.
+ *
+ * Can be useful to get information about an application with an implicit parameter that is materialized during current macro expansion.
+ * If we're in an implicit macro being expanded, it's included in this list.
+ *
+ * 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[ImplicitCandidate]
+
+ /** Information about one of the currently considered implicit candidates.
+ * Candidates are used in plural form, because implicit parameters may themselves have implicit parameters,
+ * hence implicit searches can recursively trigger other implicit searches.
+ *
+ * Can be useful to get information about an application with an implicit parameter that is materialized during current macro expansion.
+ * If we're in an implicit macro being expanded, it's included in this list.
+ *
+ * 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.
+ */
+ def enclosingImplicits: List[ImplicitCandidate]
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/runtime/Gil.scala b/src/reflect/scala/reflect/runtime/Gil.scala
new file mode 100644
index 0000000000..0edb1e5748
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/Gil.scala
@@ -0,0 +1,25 @@
+package scala.reflect
+package runtime
+
+private[reflect] trait Gil {
+ self: SymbolTable =>
+
+ // fixme... please...
+ // there are the following avenues of optimization we discussed with Roland:
+ // 1) replace PackageScope locks with ConcurrentHashMap, because PackageScope materializers seem to be idempotent
+ // 2) unlock unpickling completers by verifying that they are idempotent or moving non-idempotent parts
+ // 3) remove the necessity in global state for isSubType
+ private lazy val gil = new java.util.concurrent.locks.ReentrantLock
+
+ @inline final def gilSynchronized[T](body: => T): T = {
+ if (isCompilerUniverse) body
+ else {
+ try {
+ gil.lock()
+ body
+ } finally {
+ gil.unlock()
+ }
+ }
+ }
+}
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index 9c0781ca06..6584d80de3 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package runtime
import scala.ref.WeakReference
@@ -6,25 +7,22 @@ import scala.collection.mutable.WeakHashMap
import java.lang.{Class => jClass, Package => jPackage}
import java.lang.reflect.{
- Method => jMethod, Constructor => jConstructor, Modifier => jModifier, Field => jField,
+ Method => jMethod, Constructor => jConstructor, Field => jField,
Member => jMember, Type => jType, TypeVariable => jTypeVariable, Array => jArray,
+ AccessibleObject => jAccessibleObject,
GenericDeclaration, GenericArrayType, ParameterizedType, WildcardType, AnnotatedElement }
import java.lang.annotation.{Annotation => jAnnotation}
import java.io.IOException
-import internal.MissingRequirementError
+import scala.reflect.internal.{ MissingRequirementError, JavaAccFlags, JMethodOrConstructor }
import internal.pickling.ByteCodecs
-import internal.ClassfileConstants._
import internal.pickling.UnPickler
-import scala.collection.mutable.{ HashMap, ListBuffer }
+import scala.collection.mutable.{ HashMap, ListBuffer, ArrayBuffer }
import internal.Flags._
-//import scala.tools.nsc.util.ScalaClassLoader
-//import scala.tools.nsc.util.ScalaClassLoader._
-import ReflectionUtils.{staticSingletonInstance, innerSingletonInstance, scalacShouldntLoadClass}
+import ReflectionUtils._
import scala.language.existentials
import scala.runtime.{ScalaRunTime, BoxesRunTime}
-import scala.reflect.internal.util.Collections._
-private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { thisUniverse: SymbolTable =>
+private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse with TwoWayCaches { thisUniverse: SymbolTable =>
private lazy val mirrors = new WeakHashMap[ClassLoader, WeakReference[JavaMirror]]()
@@ -35,41 +33,39 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
jm
}
- override type RuntimeClass = java.lang.Class[_]
-
override type Mirror = JavaMirror
+ implicit val MirrorTag: ClassTag[Mirror] = ClassTag[Mirror](classOf[JavaMirror])
override lazy val rootMirror: Mirror = createMirror(NoSymbol, rootClassLoader)
// overriden by ReflectGlobal
def rootClassLoader: ClassLoader = this.getClass.getClassLoader
- trait JavaClassCompleter extends FlagAssigningCompleter
-
- def init() = {
- definitions.AnyValClass // force it.
-
- // establish root association to avoid cyclic dependency errors later
- rootMirror.classToScala(classOf[java.lang.Object]).initialize
+ trait JavaClassCompleter
- // println("initializing definitions")
- definitions.init()
- }
-
- def runtimeMirror(cl: ClassLoader): Mirror = mirrors get cl match {
- case Some(WeakReference(m)) => m
- case _ => createMirror(rootMirror.RootClass, cl)
+ def runtimeMirror(cl: ClassLoader): Mirror = gilSynchronized {
+ mirrors get cl match {
+ case Some(WeakReference(m)) => m
+ case _ => createMirror(rootMirror.RootClass, cl)
+ }
}
/** The API of a mirror for a reflective universe */
class JavaMirror(owner: Symbol,
- /** Class loader that is a mastermind behind the reflexive mirror */
+ /* Class loader that is a mastermind behind the reflexive mirror */
val classLoader: ClassLoader
) extends Roots(owner) with super.JavaMirror { thisMirror =>
val universe: thisUniverse.type = thisUniverse
import definitions._
+ private[reflect] lazy val runDefinitions = new definitions.RunDefinitions // only one "run" in the reflection universe
+ import runDefinitions._
+
+ override lazy val RootPackage = (new RootPackage with SynchronizedTermSymbol).markFlagsCompleted(mask = AllFlags)
+ override lazy val RootClass = (new RootClass with SynchronizedModuleClassSymbol).markFlagsCompleted(mask = AllFlags)
+ override lazy val EmptyPackage = (new EmptyPackage with SynchronizedTermSymbol).markFlagsCompleted(mask = AllFlags)
+ override lazy val EmptyPackageClass = (new EmptyPackageClass with SynchronizedModuleClassSymbol).markFlagsCompleted(mask = AllFlags)
/** The lazy type for root.
*/
@@ -84,19 +80,16 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
// the same thing is done by the `missingHook` below
override def staticPackage(fullname: String): ModuleSymbol =
try super.staticPackage(fullname)
- catch {
- case _: MissingRequirementError =>
- makeScalaPackage(fullname)
- }
+ catch { case _: ScalaReflectionException => makeScalaPackage(fullname) }
// ----------- Caching ------------------------------------------------------------------
- private val classCache = new TwoWayCache[jClass[_], ClassSymbol]
- private val packageCache = new TwoWayCache[Package, ModuleSymbol]
- private val methodCache = new TwoWayCache[jMethod, MethodSymbol]
+ 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]
+ private val fieldCache = new TwoWayCache[jField, TermSymbol]
+ private val tparamCache = new TwoWayCache[jTypeVariable[_ <: GenericDeclaration], TypeSymbol]
private[runtime] def toScala[J: HasJavaClass, S](cache: TwoWayCache[J, S], key: J)(body: (JavaMirror, J) => S): S =
cache.toScala(key){
@@ -104,39 +97,36 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
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 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 jclazz: jClass[_] => jclazz
+ case jmeth: jMethod => jmeth.getDeclaringClass
case jconstr: jConstructor[_] => jconstr.getDeclaringClass
}
})
// ----------- Implementations of mirror operations and classes -------------------
- private def ErrorInnerClass(sym: Symbol) = throw new ScalaReflectionException(s"$sym is an inner class, use reflectClass on an InstanceMirror to obtain its ClassMirror")
- private def ErrorInnerModule(sym: Symbol) = throw new ScalaReflectionException(s"$sym is an inner module, use reflectModule on an InstanceMirror to obtain its ModuleMirror")
- private def ErrorStaticClass(sym: Symbol) = throw new ScalaReflectionException(s"$sym is a static class, use reflectClass on a RuntimeMirror to obtain its ClassMirror")
- private def ErrorStaticModule(sym: Symbol) = throw new ScalaReflectionException(s"$sym is a static module, use reflectModule on a RuntimeMirror to obtain its ModuleMirror")
- private def ErrorNotMember(sym: Symbol, owner: Symbol) = throw new ScalaReflectionException(s"expected a member of $owner, you provided ${sym.kindString} ${sym.fullName}")
- private def ErrorNotField(sym: Symbol) = throw new ScalaReflectionException(s"expected a field or an accessor method symbol, you provided $sym")
- private def ErrorNonExistentField(sym: Symbol) = throw new ScalaReflectionException(
+ private def abort(msg: String) = throw new ScalaReflectionException(msg)
+
+ private def ErrorInnerClass(sym: Symbol) = abort(s"$sym is an inner class, use reflectClass on an InstanceMirror to obtain its ClassMirror")
+ private def ErrorInnerModule(sym: Symbol) = abort(s"$sym is an inner module, use reflectModule on an InstanceMirror to obtain its ModuleMirror")
+ private def ErrorStaticClass(sym: Symbol) = abort(s"$sym is a static class, use reflectClass on a RuntimeMirror to obtain its ClassMirror")
+ private def ErrorStaticModule(sym: Symbol) = abort(s"$sym is a static module, use reflectModule on a RuntimeMirror to obtain its ModuleMirror")
+ private def ErrorNotMember(sym: Symbol, owner: Symbol) = abort(s"expected a member of $owner, you provided ${sym.kindString} ${sym.fullName}")
+ private def ErrorNotField(sym: Symbol) = abort(s"expected a field or an accessor method symbol, you provided $sym")
+ private def ErrorNotConstructor(sym: Symbol, owner: Symbol) = abort(s"expected a constructor of $owner, you provided $sym")
+ private def ErrorArrayConstructor(sym: Symbol, owner: Symbol) = abort(s"Cannot instantiate arrays with mirrors. Consider using `scala.reflect.ClassTag(<class of element>).newArray(<length>)` instead")
+ private def ErrorFree(member: Symbol, freeType: Symbol) = abort(s"cannot reflect ${member.kindString} ${member.name}, because it's a member of a weak type ${freeType.name}")
+ private def ErrorNonExistentField(sym: Symbol) = abort(
sm"""Scala field ${sym.name} isn't represented as a Java field, neither it has a Java accessor method
|note that private parameters of class constructors don't get mapped onto fields and/or accessors,
|unless they are used outside of their declaring constructors.""")
- @deprecated("corresponding check has been removed from FieldMirror.set, this method is also being phased out", "2.11.0")
- private def ErrorSetImmutableField(sym: Symbol) = throw new ScalaReflectionException(s"cannot set an immutable field ${sym.name}")
- private def ErrorNotConstructor(sym: Symbol, owner: Symbol) = throw new ScalaReflectionException(s"expected a constructor of $owner, you provided $sym")
- private def ErrorFree(member: Symbol, freeType: Symbol) = throw new ScalaReflectionException(s"cannot reflect ${member.kindString} ${member.name}, because it's a member of a weak type ${freeType.name}")
/** Helper functions for extracting typed values from a (Class[_], Any)
* representing an annotation argument.
@@ -152,7 +142,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
object ConstantArg {
def enumToSymbol(enum: Enum[_]): Symbol = {
val staticPartOfEnum = classToScala(enum.getClass).companionSymbol
- staticPartOfEnum.typeSignature.declaration(enum.name: TermName)
+ staticPartOfEnum.info.declaration(enum.name: TermName)
}
def unapply(schemaAndValue: (jClass[_], Any)): Option[Any] = schemaAndValue match {
@@ -214,7 +204,6 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
case _ => body
}
}
-
private def checkMemberOf(sym: Symbol, owner: ClassSymbol) {
if (sym.owner == AnyClass || sym.owner == AnyRefClass || sym.owner == ObjectClass) {
// do nothing
@@ -229,6 +218,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
private def checkConstructorOf(sym: Symbol, owner: ClassSymbol) {
if (!sym.isClassConstructor) ErrorNotConstructor(sym, owner)
+ if (owner == ArrayClass) ErrorArrayConstructor(sym, owner)
ensuringNotFree(sym) {
if (!owner.info.decls.toList.contains(sym)) ErrorNotConstructor(sym, owner)
}
@@ -240,16 +230,12 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
if (staticClazz.isPrimitive) staticClazz else dynamicClazz
}
- private class JavaInstanceMirror[T: ClassTag](val instance: T)
- extends InstanceMirror {
+ private class JavaInstanceMirror[T: ClassTag](val instance: T) extends InstanceMirror {
def symbol = thisMirror.classSymbol(preciseClass(instance))
def reflectField(field: TermSymbol): FieldMirror = {
checkMemberOf(field, symbol)
if ((field.isMethod && !field.isAccessor) || field.isModule) ErrorNotField(field)
- val name =
- if (field.isGetter) nme.getterToLocal(field.name)
- else if (field.isSetter) nme.getterToLocal(nme.setterToGetter(field.name))
- else field.name
+ val name = if (field.isAccessor) field.localName else field.name
val field1 = (field.owner.info decl name).asTerm
try fieldToJava(field1)
catch {
@@ -259,7 +245,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
}
def reflectMethod(method: MethodSymbol): MethodMirror = {
checkMemberOf(method, symbol)
- mkJavaMethodMirror(instance, method)
+ mkMethodMirror(instance, method)
}
def reflectClass(cls: ClassSymbol): ClassMirror = {
if (cls.isStatic) ErrorStaticClass(cls)
@@ -274,105 +260,189 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
override def toString = s"instance mirror for $instance"
}
- private class JavaFieldMirror(val receiver: Any, val symbol: TermSymbol)
+ // caches value class metadata, so that we minimize the work that needs to be done during Mirror.apply
+ private class DerivedValueClassMetadata(info: Type) {
+ val symbol = info.typeSymbol
+ val isDerivedValueClass = symbol.isDerivedValueClass
+ lazy val boxer = runtimeClass(symbol.toType).getDeclaredConstructors().head
+ lazy val unboxer = {
+ val fields @ (field :: _) = symbol.toType.decls.collect{ case ts: TermSymbol if ts.isParamAccessor && ts.isMethod => ts }.toList
+ assert(fields.length == 1, s"$symbol: $fields")
+ runtimeClass(symbol.asClass).getDeclaredMethod(field.name.toString)
+ }
+ }
+
+ private class JavaFieldMirror(val receiver: Any, val symbol: TermSymbol, metadata: DerivedValueClassMetadata)
extends FieldMirror {
- lazy val jfield = {
- val jfield = fieldToJava(symbol)
- if (!jfield.isAccessible) jfield.setAccessible(true)
- jfield
+ def this(receiver: Any, symbol: TermSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.info))
+ def bind(newReceiver: Any) = new JavaFieldMirror(newReceiver, symbol, metadata)
+ import metadata._
+
+ lazy val jfield = ensureAccessible(fieldToJava(symbol))
+ def get = {
+ val value = jfield get receiver
+ if (isDerivedValueClass) boxer.newInstance(value) else value
}
- def get = jfield.get(receiver)
def set(value: Any) = {
// it appears useful to be able to set values of vals, therefore I'm disabling this check
// if (!symbol.isMutable) ErrorSetImmutableField(symbol)
- jfield.set(receiver, value)
- }
- // this dummy method is necessary to prevent the optimizer from stripping off ErrorSetImmutableField
- // which would break binary compatibility with 2.10.0
- private def dummy(symbol: Symbol) = ErrorSetImmutableField(symbol)
- override def toString = s"field mirror for ${symbol.fullName} (bound to $receiver)"
- }
-
- private def showMethodSig(symbol: MethodSymbol): String = {
- var sig = s"${symbol.fullName}"
- if (symbol.typeParams.nonEmpty) {
- def showTparam(tparam: Symbol) =
- tparam.typeSignature match {
- case tpe @ TypeBounds(_, _) => s"${tparam.name}$tpe"
- case _ => tparam.name
- }
- def showTparams(tparams: List[Symbol]) = "[" + (tparams map showTparam mkString ", ") + "]"
- sig += showTparams(symbol.typeParams)
- }
- if (symbol.paramss.nonEmpty) {
- def showParam(param: Symbol) = s"${param.name}: ${param.typeSignature}"
- def showParams(params: List[Symbol]) = {
- val s_mods = if (params.nonEmpty && params(0).hasFlag(IMPLICIT)) "implicit " else ""
- val s_params = params map showParam mkString ", "
- "(" + s_mods + s_params + ")"
- }
- def showParamss(paramss: List[List[Symbol]]) = paramss map showParams mkString ""
- sig += showParamss(symbol.paramss)
+ jfield.set(receiver, if (isDerivedValueClass) unboxer.invoke(value) else value)
}
- sig += s": ${symbol.returnType}"
- sig
+
+ override def toString = s"field mirror for ${showDecl(symbol)} (bound to $receiver)"
}
// the "symbol == Any_getClass || symbol == Object_getClass" test doesn't cut it
// because both AnyVal and its primitive descendants define their own getClass methods
- private def isGetClass(meth: MethodSymbol) = meth.name.toString == "getClass" && meth.paramss.flatten.isEmpty
+ private def isGetClass(meth: MethodSymbol) = (meth.name string_== "getClass") && meth.paramss.flatten.isEmpty
private def isStringConcat(meth: MethodSymbol) = meth == String_+ || (meth.owner.isPrimitiveValueClass && meth.returnType =:= StringClass.toType)
lazy val bytecodelessMethodOwners = Set[Symbol](AnyClass, AnyValClass, AnyRefClass, ObjectClass, ArrayClass) ++ ScalaPrimitiveValueClasses
lazy val bytecodefulObjectMethods = Set[Symbol](Object_clone, Object_equals, Object_finalize, Object_hashCode, Object_toString,
Object_notify, Object_notifyAll) ++ ObjectClass.info.member(nme.wait_).asTerm.alternatives.map(_.asMethod)
private def isBytecodelessMethod(meth: MethodSymbol): Boolean = {
- if (isGetClass(meth) || isStringConcat(meth) || meth.owner.isPrimitiveValueClass || meth == Predef_classOf || meth.isTermMacro) return true
+ if (isGetClass(meth) || isStringConcat(meth) || meth.owner.isPrimitiveValueClass || meth == runDefinitions.Predef_classOf || meth.isMacro) return true
bytecodelessMethodOwners(meth.owner) && !bytecodefulObjectMethods(meth)
}
+ private def isByNameParam(p: Type) = isByNameParamType(p)
+ private def isValueClassParam(p: Type) = p.typeSymbol.isDerivedValueClass
+
// unlike other mirrors, method mirrors are created by a factory
// that's because we want to have decent performance
// therefore we move special cases into separate subclasses
// rather than have them on a hot path them in a unified implementation of the `apply` method
- private def mkJavaMethodMirror[T: ClassTag](receiver: T, symbol: MethodSymbol): JavaMethodMirror = {
- if (isBytecodelessMethod(symbol)) new JavaBytecodelessMethodMirror(receiver, symbol)
- else if (symbol.paramss.flatten exists (p => isByNameParamType(p.info))) new JavaByNameMethodMirror(receiver, symbol)
- else new JavaVanillaMethodMirror(receiver, symbol)
+ private def mkMethodMirror[T: ClassTag](receiver: T, symbol: MethodSymbol): MethodMirror = {
+ def existsParam(pred: Type => Boolean) = symbol.paramss.flatten.map(_.info).exists(pred)
+ if (isBytecodelessMethod(symbol)) new BytecodelessMethodMirror(receiver, symbol)
+ else if (existsParam(isByNameParam) || existsParam(isValueClassParam)) new JavaTransformingMethodMirror(receiver, symbol)
+ else {
+ symbol.paramss.flatten.length match {
+ case 0 => new JavaVanillaMethodMirror0(receiver, symbol)
+ case 1 => new JavaVanillaMethodMirror1(receiver, symbol)
+ case 2 => new JavaVanillaMethodMirror2(receiver, symbol)
+ case 3 => new JavaVanillaMethodMirror3(receiver, symbol)
+ case 4 => new JavaVanillaMethodMirror4(receiver, symbol)
+ case _ => new JavaVanillaMethodMirror(receiver, symbol)
+ }
+ }
}
- private abstract class JavaMethodMirror(val symbol: MethodSymbol)
- extends MethodMirror {
- lazy val jmeth = {
- val jmeth = methodToJava(symbol)
- if (!jmeth.isAccessible) jmeth.setAccessible(true)
- jmeth
+ private abstract class JavaMethodMirror(val symbol: MethodSymbol, protected val ret: DerivedValueClassMetadata) extends MethodMirror {
+ lazy val jmeth = ensureAccessible(methodToJava(symbol))
+ lazy val jconstr = ensureAccessible(constructorToJava(symbol))
+
+ def jinvokeraw(args: Seq[Any]) =
+ if (!symbol.isConstructor) jmeth.invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*)
+ else if (receiver == null) jconstr.newInstance(args.asInstanceOf[Seq[AnyRef]]: _*)
+ else jconstr.newInstance((receiver +: args).asInstanceOf[Seq[AnyRef]]: _*)
+ def jinvoke(args: Seq[Any]): Any = {
+ val result = jinvokeraw(args)
+ if (!symbol.isConstructor && jmeth.getReturnType == java.lang.Void.TYPE) ()
+ else if (!symbol.isConstructor && ret.isDerivedValueClass) ret.boxer.newInstance(result.asInstanceOf[AnyRef])
+ else result
}
- def jinvoke(jmeth: jMethod, receiver: Any, args: Seq[Any]): Any = {
- val result = jmeth.invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*)
- if (jmeth.getReturnType == java.lang.Void.TYPE) ()
- else result
+ override def toString = {
+ val what = if (symbol.isConstructor) "constructor mirror" else "method mirror"
+ s"$what for ${showDecl(symbol)} (bound to $receiver)"
}
+ }
+
+ private class JavaVanillaMethodMirror(val receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata)
+ extends JavaMethodMirror(symbol, ret) {
+ def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType))
+ def bind(newReceiver: Any) = new JavaVanillaMethodMirror(newReceiver, symbol, ret)
+ def apply(args: Any*): Any = jinvoke(args)
+ }
+
+ private class JavaVanillaMethodMirror0(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata)
+ extends JavaVanillaMethodMirror(receiver, symbol, ret) {
+ def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType))
+ override def bind(newReceiver: Any) = new JavaVanillaMethodMirror0(newReceiver, symbol, ret)
+ override def jinvokeraw(args: Seq[Any]) =
+ if (!symbol.isConstructor) jmeth.invoke(receiver)
+ else if (receiver == null) jconstr.newInstance()
+ else jconstr.newInstance(receiver.asInstanceOf[AnyRef])
+ }
+
+ private class JavaVanillaMethodMirror1(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata)
+ extends JavaVanillaMethodMirror(receiver, symbol, ret) {
+ def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType))
+ override def bind(newReceiver: Any) = new JavaVanillaMethodMirror1(newReceiver, symbol, ret)
+ override def jinvokeraw(args: Seq[Any]) =
+ if (!symbol.isConstructor) jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef])
+ else if (receiver == null) jconstr.newInstance(args(0).asInstanceOf[AnyRef])
+ else jconstr.newInstance(receiver.asInstanceOf[AnyRef], args(0).asInstanceOf[AnyRef])
+ }
+
+ private class JavaVanillaMethodMirror2(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata)
+ extends JavaVanillaMethodMirror(receiver, symbol, ret) {
+ def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType))
+ override def bind(newReceiver: Any) = new JavaVanillaMethodMirror2(newReceiver, symbol, ret)
+ override def jinvokeraw(args: Seq[Any]) =
+ if (!symbol.isConstructor) jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef])
+ else if (receiver == null) jconstr.newInstance(args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef])
+ else jconstr.newInstance(receiver.asInstanceOf[AnyRef], args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef])
+ }
+
+ private class JavaVanillaMethodMirror3(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata)
+ extends JavaVanillaMethodMirror(receiver, symbol, ret) {
+ def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType))
+ override def bind(newReceiver: Any) = new JavaVanillaMethodMirror3(newReceiver, symbol, ret)
+ override def jinvokeraw(args: Seq[Any]) =
+ if (!symbol.isConstructor) jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef])
+ else if (receiver == null) jconstr.newInstance(args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef])
+ else jconstr.newInstance(receiver.asInstanceOf[AnyRef], args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef])
+ }
- override def toString = s"method mirror for ${showMethodSig(symbol)} (bound to $receiver)"
+ private class JavaVanillaMethodMirror4(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata)
+ extends JavaVanillaMethodMirror(receiver, symbol, ret) {
+ def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType))
+ override def bind(newReceiver: Any) = new JavaVanillaMethodMirror4(newReceiver, symbol, ret)
+ override def jinvokeraw(args: Seq[Any]) =
+ if (!symbol.isConstructor) jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef], args(3).asInstanceOf[AnyRef])
+ else if (receiver == null) jconstr.newInstance(args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef], args(3).asInstanceOf[AnyRef])
+ else jconstr.newInstance(receiver.asInstanceOf[AnyRef], args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef], args(3).asInstanceOf[AnyRef])
}
- private class JavaVanillaMethodMirror(val receiver: Any, symbol: MethodSymbol)
- extends JavaMethodMirror(symbol) {
- def apply(args: Any*): Any = jinvoke(jmeth, receiver, args)
+ // caches MethodSymbol metadata, so that we minimize the work that needs to be done during Mirror.apply
+ // TODO: vararg is only supported in the last parameter list (SI-6182), so we don't need to worry about the rest for now
+ private class MethodMetadata(symbol: MethodSymbol) {
+ private val params = symbol.paramss.flatten.toArray
+ private val vcMetadata = params.map(p => new DerivedValueClassMetadata(p.info))
+ val isByName = params.map(p => isByNameParam(p.info))
+ def isDerivedValueClass(i: Int) = vcMetadata(i).isDerivedValueClass
+ def paramUnboxers(i: Int) = vcMetadata(i).unboxer
+ val paramCount = params.length
+ val ret = new DerivedValueClassMetadata(symbol.returnType)
}
- private class JavaByNameMethodMirror(val receiver: Any, symbol: MethodSymbol)
- extends JavaMethodMirror(symbol) {
+ private class JavaTransformingMethodMirror(val receiver: Any, symbol: MethodSymbol, metadata: MethodMetadata)
+ extends JavaMethodMirror(symbol, metadata.ret) {
+ def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new MethodMetadata(symbol))
+ override def bind(newReceiver: Any) = new JavaTransformingMethodMirror(newReceiver, symbol, metadata)
+ import metadata._
+
def apply(args: Any*): Any = {
- val transformed = map2(args.toList, symbol.paramss.flatten)((arg, param) => if (isByNameParamType(param.info)) () => arg else arg)
- jinvoke(jmeth, receiver, transformed)
+ val args1 = new Array[Any](args.length)
+ var i = 0
+ while (i < args1.length) {
+ val arg = args(i)
+ if (i >= paramCount) args1(i) = arg // don't transform varargs
+ else if (isByName(i)) args1(i) = () => arg // don't transform by-name value class params
+ else if (isDerivedValueClass(i)) args1(i) = paramUnboxers(i).invoke(arg)
+ i += 1
+ }
+ jinvoke(args1)
}
}
- private class JavaBytecodelessMethodMirror[T: ClassTag](val receiver: T, symbol: MethodSymbol)
- extends JavaMethodMirror(symbol) {
- def apply(args: Any*): Any = {
+ private class BytecodelessMethodMirror[T: ClassTag](val receiver: T, val symbol: MethodSymbol)
+ extends MethodMirror {
+ def bind(newReceiver: Any) = new BytecodelessMethodMirror(newReceiver.asInstanceOf[T], symbol)
+ override def toString = s"bytecodeless method mirror for ${showDecl(symbol)} (bound to $receiver)"
+
+ def apply(args: Any*): Any = {
// checking type conformance is too much of a hassle, so we don't do it here
// actually it's not even necessary, because we manually dispatch arguments below
val params = symbol.paramss.flatten
@@ -383,19 +453,22 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
val varargMatch = args.length >= params.length - 1 && isVarArgsList(params)
if (!perfectMatch && !varargMatch) {
val n_arguments = if (isVarArgsList(params)) s"${params.length - 1} or more" else s"${params.length}"
- var s_arguments = if (params.length == 1 && !isVarArgsList(params)) "argument" else "arguments"
- throw new ScalaReflectionException(s"${showMethodSig(symbol)} takes $n_arguments $s_arguments")
+ val s_arguments = if (params.length == 1 && !isVarArgsList(params)) "argument" else "arguments"
+ abort(s"${showDecl(symbol)} takes $n_arguments $s_arguments")
}
def objReceiver = receiver.asInstanceOf[AnyRef]
def objArg0 = args(0).asInstanceOf[AnyRef]
def objArgs = args.asInstanceOf[Seq[AnyRef]]
- def fail(msg: String) = throw new ScalaReflectionException(msg + ", it cannot be invoked with mirrors")
+ def fail(msg: String) = abort(msg + ", it cannot be invoked with mirrors")
def invokePrimitiveMethod = {
val jmeths = classOf[BoxesRunTime].getDeclaredMethods.filter(_.getName == nme.primitiveMethodName(symbol.name).toString)
assert(jmeths.length == 1, jmeths.toList)
- jinvoke(jmeths.head, null, objReceiver +: objArgs)
+ val jmeth = jmeths.head
+ val result = jmeth.invoke(null, (objReceiver +: objArgs).asInstanceOf[Seq[AnyRef]]: _*)
+ if (jmeth.getReturnType == java.lang.Void.TYPE) ()
+ else result
}
symbol match {
@@ -411,8 +484,8 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
case sym if isGetClass(sym) => preciseClass(receiver)
case Any_asInstanceOf => fail("Any.asInstanceOf requires a type argument")
case Any_isInstanceOf => fail("Any.isInstanceOf requires a type argument")
- case Object_asInstanceOf => fail("AnyRef.$asInstanceOf is an internal method")
- case Object_isInstanceOf => fail("AnyRef.$isInstanceOf is an internal method")
+ case Object_asInstanceOf => fail("AnyRef.%s is an internal method" format symbol.name)
+ case Object_isInstanceOf => fail("AnyRef.%s is an internal method" format symbol.name)
case Array_length => ScalaRunTime.array_length(objReceiver)
case Array_apply => ScalaRunTime.array_apply(objReceiver, args(0).asInstanceOf[Int])
case Array_update => ScalaRunTime.array_update(objReceiver, args(0).asInstanceOf[Int], args(1))
@@ -420,37 +493,16 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
case sym if isStringConcat(sym) => receiver.toString + objArg0
case sym if sym.owner.isPrimitiveValueClass => invokePrimitiveMethod
case sym if sym == Predef_classOf => fail("Predef.classOf is a compile-time function")
- case sym if sym.isTermMacro => fail(s"${symbol.fullName} is a macro, i.e. a compile-time function")
+ case sym if sym.isMacro => fail(s"${symbol.fullName} is a macro, i.e. a compile-time function")
case _ => abort(s"unsupported symbol $symbol when invoking $this")
}
}
}
- private class JavaConstructorMirror(val outer: AnyRef, val symbol: MethodSymbol)
- extends MethodMirror {
- override val receiver = outer
- lazy val jconstr = {
- val jconstr = constructorToJava(symbol)
- if (!jconstr.isAccessible) jconstr.setAccessible(true)
- jconstr
- }
- def apply(args: Any*): Any = {
- if (symbol.owner == ArrayClass)
- throw new ScalaReflectionException("Cannot instantiate arrays with mirrors. Consider using `scala.reflect.ClassTag(<class of element>).newArray(<length>)` instead")
-
- val effectiveArgs =
- if (outer == null) args.asInstanceOf[Seq[AnyRef]]
- else outer +: args.asInstanceOf[Seq[AnyRef]]
- jconstr.newInstance(effectiveArgs: _*)
- }
- override def toString = s"constructor mirror for ${showMethodSig(symbol)} (bound to $outer)"
- }
-
private abstract class JavaTemplateMirror
extends TemplateMirror {
def outer: AnyRef
def erasure: ClassSymbol
- lazy val signature = typeToScala(classToJava(erasure))
}
private class JavaClassMirror(val outer: AnyRef, val symbol: ClassSymbol)
@@ -459,7 +511,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
def isStatic = false
def reflectConstructor(constructor: MethodSymbol) = {
checkConstructorOf(constructor, symbol)
- new JavaConstructorMirror(outer, constructor)
+ mkMethodMirror(outer, constructor)
}
override def toString = s"class mirror for ${symbol.fullName} (bound to $outer)"
}
@@ -469,11 +521,11 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
def erasure = symbol.moduleClass.asClass
def isStatic = true
def instance = {
- if (symbol.owner.isPackageClass)
+ if (symbol.isTopLevel)
staticSingletonInstance(classLoader, symbol.fullName)
else
if (outer == null) staticSingletonInstance(classToJava(symbol.moduleClass.asClass))
- else innerSingletonInstance(outer, symbol.name)
+ else innerSingletonInstance(outer, symbol.name.toString)
}
override def toString = s"module mirror for ${symbol.fullName} (bound to $outer)"
}
@@ -497,16 +549,13 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
}
def javaClass(path: String): jClass[_] =
- Class.forName(path, true, classLoader)
+ jClass.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
- }
+ def tryJavaClass(path: String): Option[jClass[_]] = (
+ try Some(javaClass(path))
+ catch { case ex @ (_: LinkageError | _: ClassNotFoundException) => None } // TODO - log
+ )
/** The mirror that corresponds to the classloader that original defined the given Java class */
def mirrorDefining(jclazz: jClass[_]): JavaMirror = {
@@ -515,7 +564,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
}
private object unpickler extends UnPickler {
- val global: thisUniverse.type = thisUniverse
+ val symbolTable: thisUniverse.type = thisUniverse
}
/** how connected????
@@ -530,7 +579,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
def markAbsent(tpe: Type) = setAllInfos(clazz, module, tpe)
def handleError(ex: Exception) = {
markAbsent(ErrorType)
- if (settings.debug.value) ex.printStackTrace()
+ if (settings.debug) ex.printStackTrace()
val msg = ex.getMessage()
MissingRequirementError.signal(
(if (msg eq null) "reflection error while loading " + clazz.name
@@ -562,7 +611,9 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
info(s"unpickling Scala $clazz and $module, owner = ${clazz.owner}")
val bytes = ssig.getBytes
val len = ByteCodecs.decode(bytes)
+ assignAssociatedFile(clazz, module, jclazz)
unpickler.unpickle(bytes take len, 0, clazz, module, jclazz.getName)
+ markAllCompleted(clazz, module)
case None =>
loadBytes[Array[String]]("scala.reflect.ScalaLongSignature") match {
case Some(slsig) =>
@@ -570,11 +621,13 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
val encoded = slsig flatMap (_.getBytes)
val len = ByteCodecs.decode(encoded)
val decoded = encoded.take(len)
+ assignAssociatedFile(clazz, module, jclazz)
unpickler.unpickle(decoded, 0, clazz, module, jclazz.getName)
+ markAllCompleted(clazz, module)
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))
+ initClassAndModule(clazz, module, new FromJavaClassCompleter(clazz, module, jclazz))
}
}
} catch {
@@ -593,6 +646,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
private def createTypeParameter(jtvar: jTypeVariable[_ <: GenericDeclaration]): TypeSymbol = {
val tparam = sOwner(jtvar).newTypeParameter(newTypeName(jtvar.getName))
.setInfo(new TypeParamCompleter(jtvar))
+ markFlagsCompleted(tparam)(mask = AllFlags)
tparamCache enter (jtvar, tparam)
tparam
}
@@ -605,9 +659,16 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
override def load(sym: Symbol) = complete(sym)
override def complete(sym: Symbol) = {
sym setInfo TypeBounds.upper(glb(jtvar.getBounds.toList map typeToScala map objToAny))
+ markAllCompleted(sym)
}
}
+ private def assignAssociatedFile(clazz: Symbol, module: Symbol, jclazz: jClass[_]): Unit = {
+ val associatedFile = ReflectionUtils.associatedFile(jclazz)
+ clazz.associatedFile = associatedFile
+ if (module != NoSymbol) module.associatedFile = associatedFile
+ }
+
/**
* Copy all annotations of Java annotated element `jann` over to Scala symbol `sym`.
* Also creates `@throws` annotations if necessary.
@@ -618,13 +679,22 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
sym setAnnotations (jann.getAnnotations map JavaAnnotationProxy).toList
// SI-7065: we're not using getGenericExceptionTypes here to be consistent with ClassfileParser
val jexTpes = jann match {
- case jm: jMethod => jm.getExceptionTypes.toList
+ case jm: jMethod => jm.getExceptionTypes.toList
case jconstr: jConstructor[_] => jconstr.getExceptionTypes.toList
- case _ => Nil
+ case _ => Nil
}
jexTpes foreach (jexTpe => sym.addThrowsAnnotation(classSymbol(jexTpe)))
}
+ private implicit class jClassOps(val clazz: jClass[_]) {
+ def javaFlags: JavaAccFlags = JavaAccFlags(clazz)
+ def scalaFlags: Long = javaFlags.toScalaFlags
+ }
+ private implicit class jMemberOps(val member: jMember) {
+ def javaFlags: JavaAccFlags = JavaAccFlags(member)
+ def scalaFlags: Long = javaFlags.toScalaFlags
+ }
+
/**
* 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
@@ -634,7 +704,16 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
* @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 with JavaClassCompleter with FlagAssigningCompleter {
+ private class FromJavaClassCompleter(clazz: Symbol, module: Symbol, jclazz: jClass[_]) extends LazyType with JavaClassCompleter with FlagAgnosticCompleter {
+ // one doesn't need to do non-trivial computations to assign flags for Java-based reflection artifacts
+ // therefore I'm moving flag-assigning logic from completion to construction
+ val flags = jclazz.scalaFlags
+ clazz setFlag (flags | JAVA)
+ if (module != NoSymbol) {
+ module setFlag (flags & PRIVATE | JAVA)
+ module.moduleClass setFlag (flags & PRIVATE | JAVA)
+ }
+ markFlagsCompleted(clazz, module)(mask = AllFlags)
/** used to avoid cycles while initializing classes */
private var parentsLevel = 0
@@ -644,14 +723,9 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
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)
- }
- relatedSymbols foreach (importPrivateWithinFromJavaFlags(_, jclazz.getModifiers))
+ assignAssociatedFile(clazz, module, jclazz)
+ propagatePackageBoundary(jclazz, relatedSymbols: _*)
copyAnnotations(clazz, jclazz)
// to do: annotations to set also for module?
@@ -665,18 +739,19 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
override def complete(sym: Symbol): Unit = {
load(sym)
completeRest()
+ markAllCompleted(clazz, module)
}
- def completeRest(): Unit = thisUniverse.synchronized {
+ def completeRest(): Unit = gilSynchronized {
val tparams = clazz.rawInfo.typeParams
val parents = try {
parentsLevel += 1
val jsuperclazz = jclazz.getGenericSuperclass
val ifaces = jclazz.getGenericInterfaces.toList map typeToScala
- val isAnnotation = (jclazz.getModifiers & JAVA_ACC_ANNOTATION) != 0
+ val isAnnotation = JavaAccFlags(jclazz).isAnnotation
if (isAnnotation) AnnotationClass.tpe :: ClassfileAnnotationClass.tpe :: ifaces
- else (if (jsuperclazz == null) AnyClass.tpe else typeToScala(jsuperclazz)) :: ifaces
+ else (if (jsuperclazz == null) AnyTpe else typeToScala(jsuperclazz)) :: ifaces
} finally {
parentsLevel -= 1
}
@@ -685,7 +760,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
module.moduleClass setInfo new ClassInfoType(List(), newScope, module.moduleClass)
}
- def enter(sym: Symbol, mods: Int) = followStatic(clazz, module, mods).info.decls enter sym
+ def enter(sym: Symbol, mods: JavaAccFlags) = followStatic(clazz, module, mods).info.decls enter sym
def enterEmptyCtorIfNecessary(): Unit = {
if (jclazz.getConstructors.isEmpty)
@@ -697,23 +772,15 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
// no need to call enter explicitly
}
- 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 ::= { () =>
+ jclazz.getDeclaredFields foreach (f => enter(jfieldAsScala(f), f.javaFlags))
+ jclazz.getDeclaredMethods foreach (m => enter(jmethodAsScala(m), m.javaFlags))
+ jclazz.getConstructors foreach (c => enter(jconstrAsScala(c), c.javaFlags))
enterEmptyCtorIfNecessary()
-
- } :: pendingLoadActions
+ }
if (parentsLevel == 0) {
- while (!pendingLoadActions.isEmpty) {
+ while (pendingLoadActions.nonEmpty) {
val item = pendingLoadActions.head
pendingLoadActions = pendingLoadActions.tail
item()
@@ -724,6 +791,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
class LazyPolyType(override val typeParams: List[Symbol]) extends LazyType with FlagAgnosticCompleter {
override def complete(sym: Symbol) {
completeRest()
+ markAllCompleted(clazz, module)
}
}
}
@@ -732,12 +800,12 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
* 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): Symbol = followStatic(clazz, clazz.companionModule, mods)
+ private def followStatic(clazz: Symbol, mods: JavaAccFlags): Symbol = followStatic(clazz, clazz.companionModule, mods)
- private def followStatic(clazz: Symbol, module: Symbol, mods: Int): Symbol =
+ private def followStatic(clazz: Symbol, module: Symbol, mods: JavaAccFlags): Symbol =
// SI-8196 `orElse(clazz)` needed for implementation details of the backend, such as the static
// field containing the cache for structural calls.
- if (jModifier.isStatic(mods)) module.moduleClass.orElse(clazz) else clazz
+ if (mods.isStatic) module.moduleClass.orElse(clazz) else clazz
/** Methods which need to be treated with care
* because they either are getSimpleName or call getSimpleName:
@@ -769,39 +837,25 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
/**
* 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
- }
+ // @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.
+ private def sOwner(jclazz: jClass[_]): Symbol = jclazz match {
+ case PrimitiveOrArray() => ScalaPackageClass
+ case EnclosedInMethod(jowner) => methodToScala(jowner)
+ case EnclosedInConstructor(jowner) => constructorToScala(jowner)
+ case EnclosedInClass(jowner) => followStatic(classToScala(jowner), jclazz.javaFlags)
+ case EnclosedInPackage(jowner) => packageToScala(jowner).moduleClass
+ case _ => packageNameToScala(jclazz.getName take jclazz.getName.lastIndexOf('.')).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)
+ followStatic(classToScala(jmember.getDeclaringClass), jmember.javaFlags)
}
/**
@@ -817,9 +871,10 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
* 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
+ def approximateMatch(sym: Symbol, jstr: String): Boolean = (
+ (sym.name string_== jstr)
+ || sym.isPrivate && (nme.expandedName(sym.name.toTermName, sym.owner) string_== jstr)
+ )
clazz.info.decl(newTermName(jname)) orElse {
(clazz.info.decls.iterator filter (approximateMatch(_, jname))).toList match {
@@ -841,7 +896,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
private def methodToScala1(jmeth: jMethod): MethodSymbol = {
val jOwner = jmeth.getDeclaringClass
val preOwner = classToScala(jOwner)
- val owner = followStatic(preOwner, jmeth.getModifiers)
+ val owner = followStatic(preOwner, jmeth.javaFlags)
(lookup(owner, jmeth.getName) suchThat (erasesTo(_, jmeth)) orElse jmethodAsScala(jmeth))
.asMethod
}
@@ -855,26 +910,12 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
toScala(constructorCache, jconstr)(_ constructorToScala1 _)
private def constructorToScala1(jconstr: jConstructor[_]): MethodSymbol = {
- val owner = followStatic(classToScala(jconstr.getDeclaringClass), jconstr.getModifiers)
+ val owner = followStatic(classToScala(jconstr.getDeclaringClass), jconstr.javaFlags)
(lookup(owner, jconstr.getName) suchThat (erasesTo(_, jconstr)) orElse jconstrAsScala(jconstr))
.asMethod
}
/**
- * 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)).asTerm
- }
-
- /**
* The Scala package corresponding to given Java package
*/
def packageToScala(jpkg: jPackage): ModuleSymbol = packageCache.toScala(jpkg) {
@@ -896,19 +937,20 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
* The Scala package with given fully qualified name. Unlike `packageNameToScala`,
* this one bypasses the cache.
*/
- private[JavaMirrors] def makeScalaPackage(fullname: String): ModuleSymbol = {
+ private[JavaMirrors] def makeScalaPackage(fullname: String): ModuleSymbol = gilSynchronized {
val split = fullname lastIndexOf '.'
val ownerModule: ModuleSymbol =
if (split > 0) packageNameToScala(fullname take split) else this.RootPackage
val owner = ownerModule.moduleClass
val name = (fullname: TermName) drop split + 1
val opkg = owner.info decl name
- if (opkg.isPackage)
+ if (opkg.hasPackageFlag)
opkg.asModule
else if (opkg == NoSymbol) {
val pkg = owner.newPackage(name)
pkg.moduleClass setInfo new LazyPackageType
pkg setInfoAndEnter pkg.moduleClass.tpe
+ markFlagsCompleted(pkg)(mask = AllFlags)
info("made Scala "+pkg)
pkg
} else
@@ -977,8 +1019,8 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
javaTypeToValueClass(jclazz) orElse lookupClass
assert (cls.isType,
- sm"""${if (cls == NoSymbol) "not a type: symbol" else "no symbol could be"}
- | loaded from $jclazz in $owner with name $simpleName and classloader $classLoader""")
+ (if (cls != NoSymbol) s"not a type: symbol $cls" else "no symbol could be") +
+ s" loaded from $jclazz in $owner with name $simpleName and classloader $classLoader")
cls.asClass
}
@@ -995,7 +1037,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
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.asType
+ case PolyType(tparams, _) => tparams.find(_.name string_== jparam.getName).get.asType
}
}
@@ -1007,6 +1049,10 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
case jmeth: jMethod => methodToScala(jmeth)
case jconstr: jConstructor[_] => constructorToScala(jconstr)
}
+ def reflectMemberToScala(m: jMember): Symbol = m match {
+ case x: GenericDeclaration => genericDeclarationToScala(x)
+ case x: jField => jfieldAsScala(x)
+ }
/**
* Given some Java type arguments, a corresponding list of Scala types, plus potentially
@@ -1059,18 +1105,15 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
* @param jclazz The Java class
* @return A Scala class symbol that wraps all reflection info of `jclazz`
*/
- private def jclassAsScala(jclazz: jClass[_]): Symbol = {
- val clazz = sOwner(jclazz) // sOwner called outside of closure for binary compatibility
- toScala(classCache, jclazz){ (mirror, jclazz) =>
- mirror.jclassAsScala(jclazz, clazz)
- }
- }
+ private def jclassAsScala(jclazz: jClass[_]): ClassSymbol =
+ toScala(classCache, jclazz)(_ jclassAsScala1 _)
+
+ private def jclassAsScala1(jclazz: jClass[_]): ClassSymbol = {
+ val owner = sOwner(jclazz)
+ val name = scalaSimpleName(jclazz)
+ val completer = (clazz: Symbol, module: Symbol) => new FromJavaClassCompleter(clazz, module, 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, _) = createClassModule(owner, name, completer)
- clazz
+ initAndEnterClassAndModule(owner, name, completer)._1
}
/**
@@ -1084,11 +1127,13 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
private def jfieldAsScala1(jfield: jField): TermSymbol = {
val field = sOwner(jfield)
- .newValue(newTermName(jfield.getName), NoPosition, toScalaFieldFlags(jfield.getModifiers))
+ .newValue(newTermName(jfield.getName), NoPosition, jfield.scalaFlags)
.setInfo(typeToScala(jfield.getGenericType))
- fieldCache enter (jfield, field)
- importPrivateWithinFromJavaFlags(field, jfield.getModifiers)
+
+ fieldCache.enter(jfield, field)
+ propagatePackageBoundary(jfield, field)
copyAnnotations(field, jfield)
+ markAllCompleted(field)
field
}
@@ -1107,15 +1152,16 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
private def jmethodAsScala1(jmeth: jMethod): MethodSymbol = {
val clazz = sOwner(jmeth)
- val meth = clazz.newMethod(newTermName(jmeth.getName), NoPosition, toScalaMethodFlags(jmeth.getModifiers))
+ val meth = clazz.newMethod(newTermName(jmeth.getName), NoPosition, jmeth.scalaFlags)
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)
- importPrivateWithinFromJavaFlags(meth, jmeth.getModifiers)
+ propagatePackageBoundary(jmeth.javaFlags, meth)
copyAnnotations(meth, jmeth)
- if ((jmeth.getModifiers & JAVA_ACC_VARARGS) != 0) meth.setInfo(arrayToRepeated(meth.info))
+ if (jmeth.javaFlags.isVarargs) meth modifyInfo arrayToRepeated
+ markAllCompleted(meth)
meth
}
@@ -1131,26 +1177,20 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
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))
+ val constr = clazz.newConstructor(NoPosition, jconstr.scalaFlags)
constructorCache enter (jconstr, constr)
val tparams = jconstr.getTypeParameters.toList map createTypeParameter
val paramtpes = jconstr.getGenericParameterTypes.toList map typeToScala
- setMethType(constr, tparams, paramtpes, clazz.tpe)
+ setMethType(constr, tparams, paramtpes, clazz.tpe_*)
constr setInfo GenPolyType(tparams, MethodType(clazz.newSyntheticValueParams(paramtpes), clazz.tpe))
- importPrivateWithinFromJavaFlags(constr, jconstr.getModifiers)
+ propagatePackageBoundary(jconstr.javaFlags, constr)
copyAnnotations(constr, jconstr)
+ markAllCompleted(constr)
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
@@ -1166,16 +1206,18 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
valueClassToJavaType(clazz)
else if (clazz == ArrayClass)
noClass
- else if (clazz.owner.isPackageClass)
+ else if (clazz.isTopLevel)
javaClass(clazz.javaClassName)
else if (clazz.owner.isClass) {
- val childOfClass = !clazz.owner.isModuleClass
- val childOfTopLevel = clazz.owner.owner.isPackageClass
+ val childOfClass = !clazz.owner.isModuleClass
+ val childOfTopLevel = clazz.owner.isTopLevel
val childOfTopLevelObject = clazz.owner.isModuleClass && childOfTopLevel
// suggested in https://issues.scala-lang.org/browse/SI-4023?focusedCommentId=54759#comment-54759
var ownerClazz = classToJava(clazz.owner.asClass)
- if (childOfTopLevelObject) ownerClazz = Class.forName(ownerClazz.getName stripSuffix "$", true, ownerClazz.getClassLoader)
+ if (childOfTopLevelObject)
+ ownerClazz = jClass.forName(ownerClazz.getName stripSuffix "$", true, ownerClazz.getClassLoader)
+
val ownerChildren = ownerClazz.getDeclaredClasses
var fullNameOfJavaClass = ownerClazz.getName
@@ -1208,11 +1250,11 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
else sym.name.toString
/** The Java field corresponding to a given Scala field.
- * @param meth The Scala field.
+ * @param fld The Scala field.
*/
def fieldToJava(fld: TermSymbol): jField = fieldCache.toJava(fld) {
val jclazz = classToJava(fld.owner.asClass)
- val jname = nme.dropLocalSuffix(fld.name).toString
+ val jname = fld.name.dropLocal.toString
try jclazz getDeclaredField jname
catch {
case ex: NoSuchFieldException => jclazz getDeclaredField expandedName(fld)
@@ -1225,7 +1267,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
def methodToJava(meth: MethodSymbol): jMethod = methodCache.toJava(meth) {
val jclazz = classToJava(meth.owner.asClass)
val paramClasses = transformedType(meth).paramTypes map typeToJavaClass
- val jname = nme.dropLocalSuffix(meth.name).toString
+ val jname = meth.name.dropLocal.toString
try jclazz getDeclaredMethod (jname, paramClasses: _*)
catch {
case ex: NoSuchMethodException =>
@@ -1242,7 +1284,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
val effectiveParamClasses =
if (!constr.owner.owner.isStaticOwner) jclazz.getEnclosingClass +: paramClasses
else paramClasses
- jclazz getConstructor (effectiveParamClasses: _*)
+ jclazz getDeclaredConstructor (effectiveParamClasses: _*)
}
private def jArrayClass(elemClazz: jClass[_]): jClass[_] = {
@@ -1253,12 +1295,12 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
* 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.asClass)
+ case ExistentialType(_, rtpe) => typeToJavaClass(rtpe)
+ case TypeRef(_, ArrayClass, List(elemtpe)) => jArrayClass(typeToJavaClass(elemtpe))
+ case TypeRef(_, sym: ClassSymbol, _) => classToJava(sym.asClass)
case tpe @ TypeRef(_, sym: AliasTypeSymbol, _) => typeToJavaClass(tpe.dealias)
- case SingleType(_, sym: ModuleSymbol) => classToJava(sym.moduleClass.asClass)
- case _ => throw new NoClassDefFoundError("no Java class corresponding to "+tpe+" found")
+ case SingleType(_, sym: ModuleSymbol) => classToJava(sym.moduleClass.asClass)
+ case _ => throw new NoClassDefFoundError("no Java class corresponding to "+tpe+" found")
}
}
@@ -1277,11 +1319,6 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
case _ => abort(s"${sym}.enclosingRootClass = ${sym.enclosingRootClass}, which is not a RootSymbol")
}
- private lazy val syntheticCoreClasses: Map[(String, Name), Symbol] = {
- def mapEntry(sym: Symbol): ((String, Name), Symbol) = (sym.owner.fullName, sym.name) -> sym
- Map() ++ (definitions.syntheticCoreClasses map mapEntry)
- }
-
/** 1. If `owner` is a package class (but not the empty package) and `name` is a term name, make a new package
* <owner>.<name>, otherwise return NoSymbol.
* Exception: If owner is root and a java class with given name exists, create symbol in empty package instead
@@ -1291,22 +1328,20 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
override def missingHook(owner: Symbol, name: Name): Symbol = {
if (owner.hasPackageFlag) {
val mirror = mirrorThatLoaded(owner)
- // todo. this makes toolbox tests pass, but it's a mere workaround for SI-5865
-// assert((owner.info decl name) == NoSymbol, s"already exists: $owner . $name")
if (owner.isRootSymbol && mirror.tryJavaClass(name.toString).isDefined)
return mirror.EmptyPackageClass.info decl name
if (name.isTermName && !owner.isEmptyPackageClass)
return mirror.makeScalaPackage(
if (owner.isRootSymbol) name.toString else owner.fullName+"."+name)
- syntheticCoreClasses get (owner.fullName, name) match {
- case Some(tsym) =>
- // synthetic core classes are only present in root mirrors
- // because Definitions.scala, which initializes and enters them, only affects rootMirror
- // therefore we need to enter them manually for non-root mirrors
- if (mirror ne thisUniverse.rootMirror) owner.info.decls enter tsym
- return tsym
- case None =>
- }
+ if (name == tpnme.AnyRef && owner.owner.isRoot && owner.name == tpnme.scala_)
+ // when we synthesize the scala.AnyRef symbol, we need to add it to the scope of the scala package
+ // the problem is that adding to the scope implies doing something like `owner.info.decls enter anyRef`
+ // which entails running a completer for the scala package
+ // which will try to unpickle the stuff in scala/package.class
+ // which will transitively load scala.AnyRef
+ // which doesn't exist yet, because it hasn't been added to the scope yet
+ // this missing hook ties the knot without introducing synchronization problems like before
+ return definitions.AnyRefClass
}
info("*** missing: "+name+"/"+name.isTermName+"/"+owner+"/"+owner.hasPackageFlag+"/"+owner.info.decls.getClass)
super.missingHook(owner, name)
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala
index 1b69ca4e89..b5446694ed 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala
@@ -1,7 +1,11 @@
-package scala.reflect
+package scala
+package reflect
package runtime
-import internal.{SomePhase, NoPhase, Phase, TreeGen}
+import scala.reflect.internal.{TreeInfo, SomePhase}
+import scala.reflect.internal.{SymbolTable => InternalSymbolTable}
+import scala.reflect.runtime.{SymbolTable => RuntimeSymbolTable}
+import scala.reflect.api.{TreeCreator, TypeCreator, Universe}
/** An implementation of [[scala.reflect.api.Universe]] for runtime reflection using JVM classloaders.
*
@@ -9,20 +13,125 @@ import internal.{SomePhase, NoPhase, Phase, TreeGen}
*
* @contentDiagram hideNodes "*Api" "*Extractor"
*/
-class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.SymbolTable { self =>
+class JavaUniverse extends InternalSymbolTable with JavaUniverseForce with ReflectSetup with RuntimeSymbolTable { self =>
+ override def inform(msg: String): Unit = log(msg)
def picklerPhase = SomePhase
-
+ def erasurePhase = SomePhase
lazy val settings = new Settings
- def forInteractive = false
- def forScaladoc = false
+ private val isLogging = sys.props contains "scala.debug.reflect"
- def log(msg: => AnyRef): Unit = if (settings.debug.value) println(" [] "+msg)
+ def log(msg: => AnyRef): Unit = if (isLogging) Console.err.println("[reflect] " + msg)
type TreeCopier = InternalTreeCopierOps
+ implicit val TreeCopierTag: ClassTag[TreeCopier] = ClassTag[TreeCopier](classOf[TreeCopier])
def newStrictTreeCopier: TreeCopier = new StrictTreeCopier
def newLazyTreeCopier: TreeCopier = new LazyTreeCopier
+ def currentFreshNameCreator = globalFreshNameCreator
+
+ override lazy val internal: Internal = new SymbolTableInternal {
+ override def typeTagToManifest[T: ClassTag](mirror0: Any, tag: Universe # TypeTag[T]): Manifest[T] = {
+ // SI-6239: make this conversion more precise
+ val mirror = mirror0.asInstanceOf[Mirror]
+ val runtimeClass = mirror.runtimeClass(tag.in(mirror).tpe)
+ Manifest.classType(runtimeClass).asInstanceOf[Manifest[T]]
+ }
+ override def manifestToTypeTag[T](mirror0: Any, manifest: Manifest[T]): Universe # TypeTag[T] =
+ TypeTag(mirror0.asInstanceOf[Mirror], new TypeCreator {
+ def apply[U <: Universe with Singleton](mirror: scala.reflect.api.Mirror[U]): U # Type = {
+ mirror.universe match {
+ case ju: JavaUniverse =>
+ val jm = mirror.asInstanceOf[ju.Mirror]
+ val sym = jm.classSymbol(manifest.runtimeClass)
+ val tpe =
+ if (manifest.typeArguments.isEmpty) sym.toType
+ else {
+ val tags = manifest.typeArguments map (targ => ju.internal.manifestToTypeTag(jm, targ))
+ ju.appliedType(sym.toTypeConstructor, tags map (_.in(jm).tpe))
+ }
+ tpe.asInstanceOf[U # Type]
+ case u =>
+ u.internal.manifestToTypeTag(mirror.asInstanceOf[u.Mirror], manifest).in(mirror).tpe
+ }
+ }
+ })
+ }
+
+ // can't put this in runtime.Trees since that's mixed with Global in ReflectGlobal, which has the definition from internal.Trees
+ object treeInfo extends {
+ val global: JavaUniverse.this.type = JavaUniverse.this
+ } with TreeInfo
+
init()
-}
+ // ======= Initialization of runtime reflection =======
+ //
+ // This doc describes the carefully laid out sequence of actions used to initialize reflective universes.
+ //
+ // Before reading the text below, read up the section Mirrors in the reflection pre-SIP
+ // https://docs.google.com/document/d/1nAwSw4TmMplsIlzh2shYLUJ5mVh3wndDa1Zm1H6an9A/edit.
+ // Take an especially good look at Figure 2, because it illustrates fundamental principles underlying runtime reflection:
+ // 1) For each universe we have one mirror per classloader
+ // 2) Package symbols are per-mirror
+ // 3) Other symbols are per-universe, which means that a symbol (e.g. Seq on the picture) might be shared between multiple owners
+ //
+ // Main challenges that runtime reflection presents wrt initialization are:
+ // 1) Extravagant completion scheme that enters package members on-demand rather than a result of scanning a directory with class files.
+ // (That's a direct consequence of the fact that in general case we can't enumerate all classes in a classloader.
+ // As Paul rightfully mentioned, we could specialcase classloaders that point to filesystems, but that is left for future work).
+ // 2) Presence of synthetic symbols that aren't loaded by normal means (from classfiles) but are synthesized on-the-fly,
+ // and the necessity to propagate these synthetic symbols from rootMirror to other mirrors,
+ // complicated by the fact that such symbols depend on normal symbols (e.g. AnyRef depends on Object).
+ // 3) Necessity to remain thread-safe, which limits our options related to lazy initialization
+ // (E.g. we cannot use missingHook to enter synthetic symbols, because that's thread-unsafe).
+ //
+ // Directly addressing the challenge #3, we create all synthetic symbols fully in advance during init().
+ // However, it's not that simple as just calling definitions.symbolsNotPresentInBytecode.
+ // Before doing that, we need to first initialize ObjectClass, then ScalaPackageClass, and only then deal with synthetics.
+ // Below you can find a detailed explanation for that.
+ //
+ // ### Why ScalaPackageClass? ###
+ //
+ // Forcing ScalaPackageClass first thing during startup is important, because syntheticCoreClasses such as AnyRefClass
+ // need to be entered into ScalaPackageClass, which entails calling ScalaPackageClass.info.decls.enter.
+ // If ScalaPackageClass isn't initialized by that moment, the following will happen for runtime reflection:
+ // 1) Initialization of ScalaPackageClass will trigger unpickling.
+ // 2) Unpickling will need to load some auxiliary types such as, for example, String.
+ // 3) To load String, runtime reflection will call mirrorDefining(classOf[String]).
+ // 4) This, in turn, will call runtimeMirror(classOf[String].getClassLoader).
+ // 5) For some classloader configurations, the resulting mirror will be different from rootMirror.
+ // 6) In that case, initialization of the resulting mirror will try to import definitions.syntheticCoreClasses into the mirror.
+ // 7) This will force all the lazy vals corresponding to syntheticCoreClasses.
+ // 8) By that time, the completer of ScalaPackageClass will have already called setInfo on ScalaPackageClass, so there won't be any stack overflow.
+ //
+ // So far so good, no crashes, no problems, right? Not quite.
+ // If forcing of ScalaPackageClass was called by a syntheticCoreClasses lazy val,
+ // then this lazy val will be entered twice: once during step 7 and once when returning from the original call.
+ // To avoid this we need to initialize ScalaPackageClass prior to other synthetics.
+ //
+ // ### Why ObjectClass? ###
+ //
+ // 1) As explained in JavaMirrors.missingHook, initialization of ScalaPackageClass critically depends on AnyRefClass.
+ // 2) AnyRefClass is defined as "lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectTpe)",
+ // which means that initialization of AnyRefClass depends on ObjectClass.
+ // 3) ObjectClass is defined as "lazy val ObjectClass = getRequiredClass(sn.Object.toString)",
+ // which means that under some classloader configurations (see JavaMirrors.missingHook for more details)
+ // dereferencing ObjectClass might trigger an avalanche of initializations calling back into AnyRefClass
+ // while another AnyRefClass initializer is still on stack.
+ // 4) That will lead to AnyRefClass being entered two times (once when the recursive call returns and once when the original one returns)
+ // 5) That will crash PackageScope.enter that helpfully detects double-enters.
+ //
+ // Therefore, before initializing ScalaPackageClass, we must pre-initialize ObjectClass
+ def init() {
+ definitions.init()
+
+ // workaround for http://groups.google.com/group/scala-internals/browse_thread/thread/97840ba4fd37b52e
+ // constructors are by definition single-threaded, so we initialize all lazy vals (and local object) in advance
+ // in order to avoid deadlocks later (e.g. one thread holds a global reflection lock and waits for definitions.Something to initialize,
+ // whereas another thread holds a definitions.Something initialization lock and needs a global reflection lock to complete the initialization)
+
+ // TODO Convert this into a macro
+ force()
+ }
+}
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
new file mode 100644
index 0000000000..dcd262c288
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -0,0 +1,448 @@
+// Generated Code, validated by run/t6240-universe-code-gen.scala
+package scala.reflect
+package runtime
+
+trait JavaUniverseForce { self: runtime.JavaUniverse =>
+ def force() {
+ Literal(Constant(42)).duplicate
+ nme.flattenedName()
+ nme.raw
+ WeakTypeTag
+ TypeTag
+ TypeTag.Byte.tpe
+ TypeTag.Short.tpe
+ TypeTag.Char.tpe
+ TypeTag.Int.tpe
+ TypeTag.Long.tpe
+ TypeTag.Float.tpe
+ TypeTag.Double.tpe
+ TypeTag.Boolean.tpe
+ TypeTag.Unit.tpe
+ TypeTag.Any.tpe
+ TypeTag.AnyVal.tpe
+ TypeTag.AnyRef.tpe
+ TypeTag.Object.tpe
+ TypeTag.Nothing.tpe
+ TypeTag.Null.tpe
+
+ this.settings
+ this.internal
+ this.treeInfo
+ this.rootMirror
+ this.traceSymbols
+ this.perRunCaches
+ this.compat
+ this.treeBuild
+ this.FreshNameExtractor
+ this.FixedMirrorTreeCreator
+ this.FixedMirrorTypeCreator
+ this.CompoundTypeTreeOriginalAttachment
+ this.BackquotedIdentifierAttachment
+ this.ForAttachment
+ this.SyntheticUnitAttachment
+ this.SubpatternsAttachment
+ this.noPrint
+ this.typeDebug
+ this.Range
+ // inaccessible: this.posAssigner
+ this.ConsoleWriter
+ this.RefTree
+ this.PackageDef
+ this.ClassDef
+ this.ModuleDef
+ this.ValOrDefDef
+ this.ValDef
+ this.DefDef
+ this.TypeDef
+ this.LabelDef
+ this.ImportSelector
+ this.Import
+ this.Template
+ this.Block
+ this.CaseDef
+ this.Alternative
+ this.Star
+ this.Bind
+ this.UnApply
+ this.ArrayValue
+ this.Function
+ this.Assign
+ this.AssignOrNamedArg
+ this.If
+ this.Match
+ this.Return
+ this.Try
+ this.Throw
+ this.New
+ this.Typed
+ this.TypeApply
+ this.Apply
+ this.ApplyDynamic
+ this.Super
+ this.This
+ this.Select
+ this.Ident
+ this.ReferenceToBoxed
+ this.Literal
+ this.Annotated
+ this.SingletonTypeTree
+ this.SelectFromTypeTree
+ this.CompoundTypeTree
+ this.AppliedTypeTree
+ this.TypeBoundsTree
+ this.ExistentialTypeTree
+ this.TypeTree
+ this.Modifiers
+ this.EmptyTree
+ this.noSelfType
+ this.pendingSuperCall
+ this.emptyValDef
+ this.EmptyTreeTypeSubstituter
+ this.UnmappableAnnotArg
+ this.LiteralAnnotArg
+ this.ArrayAnnotArg
+ this.NestedAnnotArg
+ this.ScalaSigBytes
+ this.AnnotationInfo
+ this.Annotation
+ this.UnmappableAnnotation
+ this.ErroneousAnnotation
+ this.ThrownException
+ this.typeNames
+ this.tpnme
+ this.fulltpnme
+ this.binarynme
+ this.termNames
+ this.nme
+ this.sn
+ this.Constant
+ this.definitions
+ this.LookupSucceeded
+ this.LookupAmbiguous
+ this.LookupInaccessible
+ this.LookupNotFound
+ this.Scope
+ this.EmptyScope
+ this.Flag
+ this.KindErrors
+ this.Kind
+ this.ProperTypeKind
+ this.TypeConKind
+ this.inferKind
+ this.UnmappableTree
+ this.ErrorType
+ this.WildcardType
+ this.BoundedWildcardType
+ this.NoType
+ this.NoPrefix
+ this.ThisType
+ this.SingleType
+ this.SuperType
+ this.TypeBounds
+ this.CompoundType
+ this.baseClassesCycleMonitor
+ this.RefinedType
+ this.ClassInfoType
+ this.ConstantType
+ this.TypeRef
+ this.MethodType
+ this.NullaryMethodType
+ this.PolyType
+ this.ExistentialType
+ this.OverloadedType
+ this.ImportType
+ this.AntiPolyType
+ this.HasTypeMember
+ this.ArrayTypeRef
+ this.TypeVar
+ this.AnnotatedType
+ this.StaticallyAnnotatedType
+ this.NamedType
+ this.RepeatedType
+ this.ErasedValueType
+ this.GenPolyType
+ this.unwrapToClass
+ this.unwrapToStableClass
+ this.unwrapWrapperTypes
+ this.RecoverableCyclicReference
+ this.TypeConstraint
+ this.normalizeAliases
+ this.dropSingletonType
+ this.abstractTypesToBounds
+ this.dropIllegalStarTypes
+ this.IsDependentCollector
+ this.ApproximateDependentMap
+ this.wildcardToTypeVarMap
+ this.typeVarToOriginMap
+ this.ErroneousCollector
+ this.adaptToNewRunMap
+ this.SubTypePair
+ this.SymbolKind
+ this.NoSymbol
+ this.CyclicReference
+ this.SymbolOps
+ this.TermName
+ this.TypeName
+ this.Liftable
+ this.Unliftable
+ this.BooleanFlag
+ this.WeakTypeTag
+ this.TypeTag
+ this.Expr
+ this.NoMods
+ definitions.JavaLangPackage
+ definitions.JavaLangPackageClass
+ definitions.ScalaPackage
+ definitions.ScalaPackageClass
+ definitions.RuntimePackage
+ definitions.RuntimePackageClass
+ definitions.AnyClass
+ definitions.AnyRefClass
+ definitions.ObjectClass
+ definitions.AnyRefTpe
+ definitions.AnyTpe
+ definitions.AnyValTpe
+ definitions.BoxedUnitTpe
+ definitions.NothingTpe
+ definitions.NullTpe
+ definitions.ObjectTpe
+ definitions.SerializableTpe
+ definitions.StringTpe
+ definitions.ThrowableTpe
+ definitions.ConstantTrue
+ definitions.ConstantFalse
+ definitions.ConstantNull
+ definitions.AnyValClass
+ definitions.RuntimeNothingClass
+ definitions.RuntimeNullClass
+ definitions.NothingClass
+ definitions.NullClass
+ definitions.ClassCastExceptionClass
+ definitions.IndexOutOfBoundsExceptionClass
+ definitions.InvocationTargetExceptionClass
+ definitions.MatchErrorClass
+ definitions.NonLocalReturnControlClass
+ definitions.NullPointerExceptionClass
+ definitions.ThrowableClass
+ definitions.UninitializedErrorClass
+ definitions.UninitializedFieldConstructor
+ definitions.PartialFunctionClass
+ definitions.AbstractPartialFunctionClass
+ definitions.SymbolClass
+ definitions.StringClass
+ definitions.StringModule
+ definitions.ClassClass
+ definitions.DynamicClass
+ definitions.SysPackage
+ definitions.UnqualifiedModules
+ definitions.UnqualifiedOwners
+ definitions.PredefModule
+ definitions.SpecializableModule
+ definitions.ScalaRunTimeModule
+ definitions.SymbolModule
+ definitions.StringAddClass
+ definitions.ScalaNumberClass
+ definitions.TraitSetterAnnotationClass
+ definitions.DelayedInitClass
+ definitions.TypeConstraintClass
+ definitions.SingletonClass
+ definitions.SerializableClass
+ definitions.JavaSerializableClass
+ definitions.ComparableClass
+ definitions.JavaCloneableClass
+ definitions.JavaNumberClass
+ definitions.JavaEnumClass
+ definitions.RemoteInterfaceClass
+ definitions.RemoteExceptionClass
+ definitions.ByNameParamClass
+ definitions.JavaRepeatedParamClass
+ definitions.RepeatedParamClass
+ definitions.ConsClass
+ definitions.IteratorClass
+ definitions.IterableClass
+ definitions.ListClass
+ definitions.SeqClass
+ definitions.StringBuilderClass
+ definitions.TraversableClass
+ definitions.ListModule
+ definitions.NilModule
+ definitions.SeqModule
+ definitions.ArrayModule
+ definitions.ArrayModule_overloadedApply
+ definitions.ArrayClass
+ definitions.Array_apply
+ definitions.Array_update
+ definitions.Array_length
+ definitions.Array_clone
+ definitions.SoftReferenceClass
+ definitions.MethodClass
+ definitions.EmptyMethodCacheClass
+ definitions.MethodCacheClass
+ definitions.ScalaXmlTopScope
+ definitions.ScalaXmlPackage
+ definitions.ReflectPackage
+ definitions.ReflectApiPackage
+ definitions.ReflectRuntimePackage
+ definitions.UniverseClass
+ definitions.PartialManifestModule
+ definitions.FullManifestClass
+ definitions.FullManifestModule
+ definitions.OptManifestClass
+ definitions.NoManifest
+ definitions.TreesClass
+ definitions.ExprsClass
+ definitions.ClassTagModule
+ definitions.ClassTagClass
+ definitions.TypeTagsClass
+ definitions.ApiUniverseClass
+ definitions.JavaUniverseClass
+ definitions.MirrorClass
+ definitions.TypeCreatorClass
+ definitions.TreeCreatorClass
+ definitions.BlackboxContextClass
+ definitions.WhiteboxContextClass
+ definitions.MacroImplAnnotation
+ definitions.StringContextClass
+ definitions.QuasiquoteClass
+ definitions.QuasiquoteClass_api
+ definitions.QuasiquoteClass_api_apply
+ definitions.QuasiquoteClass_api_unapply
+ definitions.ScalaSignatureAnnotation
+ definitions.ScalaLongSignatureAnnotation
+ definitions.OptionClass
+ definitions.OptionModule
+ definitions.SomeClass
+ definitions.NoneModule
+ definitions.SomeModule
+ definitions.VarArityClass
+ definitions.ProductClass
+ definitions.TupleClass
+ definitions.FunctionClass
+ definitions.AbstractFunctionClass
+ definitions.MacroContextType
+ definitions.ProductRootClass
+ definitions.Any_$eq$eq
+ definitions.Any_$bang$eq
+ definitions.Any_equals
+ definitions.Any_hashCode
+ definitions.Any_toString
+ definitions.Any_$hash$hash
+ definitions.Any_getClass
+ definitions.Any_isInstanceOf
+ definitions.Any_asInstanceOf
+ definitions.primitiveGetClassMethods
+ definitions.getClassMethods
+ definitions.Object_$hash$hash
+ definitions.Object_$eq$eq
+ definitions.Object_$bang$eq
+ definitions.Object_eq
+ definitions.Object_ne
+ definitions.Object_isInstanceOf
+ definitions.Object_asInstanceOf
+ definitions.Object_synchronized
+ definitions.String_$plus
+ definitions.ObjectRefClass
+ definitions.VolatileObjectRefClass
+ definitions.RuntimeStaticsModule
+ definitions.BoxesRunTimeModule
+ definitions.BoxesRunTimeClass
+ definitions.BoxedNumberClass
+ definitions.BoxedCharacterClass
+ definitions.BoxedBooleanClass
+ definitions.BoxedByteClass
+ definitions.BoxedShortClass
+ definitions.BoxedIntClass
+ definitions.BoxedLongClass
+ definitions.BoxedFloatClass
+ definitions.BoxedDoubleClass
+ definitions.BoxedUnitClass
+ definitions.BoxedUnitModule
+ definitions.AnnotationClass
+ definitions.ClassfileAnnotationClass
+ definitions.StaticAnnotationClass
+ definitions.BridgeClass
+ definitions.ElidableMethodClass
+ definitions.ImplicitNotFoundClass
+ definitions.MigrationAnnotationClass
+ definitions.ScalaStrictFPAttr
+ definitions.SwitchClass
+ definitions.TailrecClass
+ definitions.VarargsClass
+ definitions.uncheckedStableClass
+ definitions.uncheckedVarianceClass
+ definitions.BeanPropertyAttr
+ definitions.BooleanBeanPropertyAttr
+ definitions.CompileTimeOnlyAttr
+ definitions.DeprecatedAttr
+ definitions.DeprecatedNameAttr
+ definitions.DeprecatedInheritanceAttr
+ definitions.DeprecatedOverridingAttr
+ definitions.NativeAttr
+ definitions.RemoteAttr
+ definitions.ScalaInlineClass
+ definitions.ScalaNoInlineClass
+ definitions.SerialVersionUIDAttr
+ definitions.SerialVersionUIDAnnotation
+ definitions.SpecializedClass
+ definitions.ThrowsClass
+ definitions.TransientAttr
+ definitions.UncheckedClass
+ definitions.UncheckedBoundsClass
+ definitions.UnspecializedClass
+ definitions.VolatileAttr
+ definitions.BeanGetterTargetClass
+ definitions.BeanSetterTargetClass
+ definitions.FieldTargetClass
+ definitions.GetterTargetClass
+ definitions.ParamTargetClass
+ definitions.SetterTargetClass
+ definitions.ObjectTargetClass
+ definitions.ClassTargetClass
+ definitions.MethodTargetClass
+ definitions.LanguageFeatureAnnot
+ definitions.languageFeatureModule
+ definitions.metaAnnotations
+ definitions.AnnotationDefaultAttr
+ definitions.isPhantomClass
+ definitions.syntheticCoreClasses
+ definitions.syntheticCoreMethods
+ definitions.hijackedCoreClasses
+ definitions.symbolsNotPresentInBytecode
+ definitions.isPossibleSyntheticParent
+ definitions.abbrvTag
+ definitions.numericWeight
+ definitions.boxedModule
+ definitions.boxedClass
+ definitions.refClass
+ definitions.volatileRefClass
+ definitions.UnitClass
+ definitions.ByteClass
+ definitions.ShortClass
+ definitions.CharClass
+ definitions.IntClass
+ definitions.LongClass
+ definitions.FloatClass
+ definitions.DoubleClass
+ definitions.BooleanClass
+ definitions.UnitTpe
+ definitions.ByteTpe
+ definitions.ShortTpe
+ definitions.CharTpe
+ definitions.IntTpe
+ definitions.LongTpe
+ definitions.FloatTpe
+ definitions.DoubleTpe
+ definitions.BooleanTpe
+ definitions.ScalaNumericValueClasses
+ definitions.ScalaValueClassesNoUnit
+ definitions.ScalaValueClasses
+
+
+ erasure.GenericArray
+ erasure.scalaErasure
+ erasure.specialScalaErasure
+ erasure.javaErasure
+ erasure.verifiedJavaErasure
+ erasure.boxingErasure
+ }
+}
diff --git a/src/reflect/scala/reflect/runtime/ReflectSetup.scala b/src/reflect/scala/reflect/runtime/ReflectSetup.scala
index 6e28fc8520..6a364ff0be 100644
--- a/src/reflect/scala/reflect/runtime/ReflectSetup.scala
+++ b/src/reflect/scala/reflect/runtime/ReflectSetup.scala
@@ -1,7 +1,8 @@
-package scala.reflect
+package scala
+package reflect
package runtime
-import internal.{SomePhase, NoPhase, Phase, TreeGen}
+import internal.{SomePhase, NoPhase, Phase}
/** A helper trait to initialize things that need to be set before JavaMirrors and other
* reflect specific traits are initialized */
diff --git a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala
index ffed3cc38e..a4bd698068 100644
--- a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala
+++ b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala
@@ -3,14 +3,18 @@
* @author Paul Phillips
*/
-package scala.reflect.runtime
+package scala
+package reflect.runtime
import java.lang.{Class => jClass}
import java.lang.reflect.{ Method, InvocationTargetException, UndeclaredThrowableException }
+import scala.reflect.internal.util.AbstractFileClassLoader
+import scala.reflect.io._
+import java.io.{File => JFile}
/** A few java-reflection oriented utility functions useful during reflection bootstrapping.
*/
-private[scala] object ReflectionUtils {
+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
@@ -33,8 +37,8 @@ private[scala] object ReflectionUtils {
def isAbstractFileClassLoader(clazz: Class[_]): Boolean = {
if (clazz == null) return false
- if (clazz.getName == "scala.tools.nsc.interpreter.AbstractFileClassLoader") return true
- return isAbstractFileClassLoader(clazz.getSuperclass)
+ if (clazz == classOf[AbstractFileClassLoader]) return true
+ isAbstractFileClassLoader(clazz.getSuperclass)
}
def inferClasspath(cl: ClassLoader): String = cl match {
case cl: java.net.URLClassLoader =>
@@ -82,4 +86,87 @@ private[scala] object ReflectionUtils {
def scalacShouldntLoadClassfile(fileName: String) = isTraitImplementation(fileName)
def scalacShouldntLoadClass(name: scala.reflect.internal.SymbolTable#Name) = scalacShouldntLoadClassfile(name + ".class")
+
+ object PrimitiveOrArray {
+ def unapply(jclazz: jClass[_]) = jclazz.isPrimitive || jclazz.isArray
+ }
+
+ class EnclosedIn[T](enclosure: jClass[_] => T) {
+ def unapply(jclazz: jClass[_]): Option[T] = if (enclosure(jclazz) != null) Some(enclosure(jclazz)) else None
+ }
+
+ object EnclosedInMethod extends EnclosedIn(_.getEnclosingMethod)
+ object EnclosedInConstructor extends EnclosedIn(_.getEnclosingConstructor)
+ object EnclosedInClass extends EnclosedIn(_.getEnclosingClass)
+ object EnclosedInPackage extends EnclosedIn(_.getPackage)
+
+ def associatedFile(clazz: Class[_]): AbstractFile = {
+ // TODO: I agree with Jason - this implementation isn't something that we'd like to support
+ // therefore I'm having it commented out and this function will now return NoAbstractFile
+ // I think we can keep the source code though, because it can be useful to the others
+ //
+ // def inferAssociatedFile(clazz: Class[_]): AbstractFile = {
+ // // http://stackoverflow.com/questions/227486/find-where-java-class-is-loaded-from
+ // try {
+ // var cl = clazz.getClassLoader()
+ // if (cl == null) {
+ // cl = ClassLoader.getSystemClassLoader()
+ // while (cl != null && cl.getParent != null) cl = cl.getParent
+ // }
+ // var result: AbstractFile = null
+ // if (cl != null) {
+ // val name = clazz.getCanonicalName()
+ // val resource = cl.getResource(name.replace(".", "/") + ".class")
+ // if (resource != null) {
+ // def fromFile(file: String) = AbstractFile.getFile(file)
+ // def fromJarEntry(jarfile: String, entrypath: String) = {
+ // val jar = fromFile(jarfile)
+ // new VirtualFile(clazz.getName, entrypath) {
+ // lazy val impl: AbstractFile = {
+ // def loop(root: AbstractFile, path: List[String]): AbstractFile = {
+ // def find(name: String) = root.iterator.find(_.name == name).getOrElse(NoAbstractFile)
+ // path match {
+ // case step :: Nil => find(step)
+ // case step :: rest => loop(find(step), rest)
+ // case Nil => NoAbstractFile
+ // }
+ // }
+ // loop(ZipArchive.fromFile(new JFile(jarfile)), entrypath.split("/").toList)
+ // }
+ // override def container = impl.container
+ // override def lastModified = impl.lastModified
+ // override def input = impl.input
+ // override def sizeOption = impl.sizeOption
+ // override def underlyingSource = Some(jar)
+ // override def toString = jarfile + "(" + entrypath + ")"
+ // }
+ // }
+ // def fallback() = new VirtualFile(clazz.getName, resource.toString)
+ // result = resource.getProtocol match {
+ // case "file" =>
+ // fromFile(resource.getFile)
+ // case "jar" =>
+ // val intrajarUrl = new java.net.URL(resource.getFile)
+ // intrajarUrl.getProtocol match {
+ // case "file" =>
+ // val file = intrajarUrl.getFile()
+ // val expectedSuffix = "!/" + name.replace(".", "/") + ".class"
+ // if (file.endsWith(expectedSuffix)) fromJarEntry(file.stripSuffix(expectedSuffix), expectedSuffix.substring(2))
+ // else fallback()
+ // case _ => fallback()
+ // }
+ // case _ =>
+ // fallback()
+ // }
+ // }
+ // }
+ // if (result != null) result else NoAbstractFile
+ // } catch {
+ // case _: Exception => NoAbstractFile
+ // }
+ // }
+ // inferAssociatedFile(clazz)
+ NoAbstractFile
+ }
}
+
diff --git a/src/reflect/scala/reflect/runtime/Settings.scala b/src/reflect/scala/reflect/runtime/Settings.scala
index 0e0cf3fc40..27d574b1de 100644
--- a/src/reflect/scala/reflect/runtime/Settings.scala
+++ b/src/reflect/scala/reflect/runtime/Settings.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package runtime
import scala.reflect.internal.settings.MutableSettings
@@ -32,12 +33,15 @@ private[reflect] class Settings extends MutableSettings {
val Xexperimental = new BooleanSetting(false)
val XfullLubs = new BooleanSetting(false)
val XnoPatmatAnalysis = new BooleanSetting(false)
- val XoldPatmat = new BooleanSetting(false)
+ val strictInference = new BooleanSetting(false)
val Xprintpos = new BooleanSetting(false)
- val Ynotnull = new BooleanSetting(false)
+ val Yposdebug = new BooleanSetting(false)
+ val Yrangepos = new BooleanSetting(false)
+ val Yshowsymowners = new BooleanSetting(false)
val Yshowsymkinds = new BooleanSetting(false)
+ val breakCycles = new BooleanSetting(false)
val debug = new BooleanSetting(false)
- val deepCloning = new BooleanSetting(false)
+ val developer = new BooleanSetting(false)
val explaintypes = new BooleanSetting(false)
val overrideObjects = new BooleanSetting(false)
val printtypes = new BooleanSetting(false)
@@ -46,4 +50,5 @@ private[reflect] class Settings extends MutableSettings {
val Yrecursion = new IntSetting(0)
val maxClassfileName = new IntSetting(255)
+ def isScala211 = true
}
diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
index b895092639..7ba68b8733 100644
--- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
+++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
@@ -1,10 +1,12 @@
-package scala.reflect
+package scala
+package reflect
package runtime
import internal.Flags
import java.lang.{Class => jClass, Package => jPackage}
import scala.collection.mutable
import scala.reflect.runtime.ReflectionUtils.scalacShouldntLoadClass
+import scala.reflect.internal.Flags._
private[reflect] trait SymbolLoaders { self: SymbolTable =>
@@ -16,37 +18,16 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
* is found, a package is created instead.
*/
class TopClassCompleter(clazz: Symbol, module: Symbol) extends SymLoader with FlagAssigningCompleter {
-// def makePackage() {
-// println("wrong guess; making package "+clazz)
-// val ptpe = newPackageType(module.moduleClass)
-// for (sym <- List(clazz, module, module.moduleClass)) {
-// sym setFlag Flags.PACKAGE
-// sym setInfo ptpe
-// }
-// }
-
+ markFlagsCompleted(clazz, module)(mask = ~TopLevelPickledFlags)
override def complete(sym: Symbol) = {
debugInfo("completing "+sym+"/"+clazz.fullName)
assert(sym == clazz || sym == module || sym == module.moduleClass)
-// try {
- atPhaseNotLaterThan(picklerPhase) {
+ slowButSafeEnteringPhaseNotLaterThan(picklerPhase) {
val loadingMirror = mirrorThatLoaded(sym)
val javaClass = loadingMirror.javaClass(clazz.javaClassName)
loadingMirror.unpickleClass(clazz, module, javaClass)
-// } catch {
-// case ex: ClassNotFoundException => makePackage()
-// case ex: NoClassDefFoundError => makePackage()
- // Note: We catch NoClassDefFoundError because there are situations
- // where a package and a class have the same name except for capitalization.
- // It seems in this case the class is loaded even if capitalization differs
- // but then a NoClassDefFound error is issued with a ("wrong name: ...")
- // reason. (I guess this is a concession to Windows).
- // The present behavior is a bit too forgiving, in that it masks
- // all class load errors, not just wrong name errors. We should try
- // to be more discriminating. To get on the right track simply delete
- // the clause above and load a collection class such as collection.Iterable.
- // You'll see an error that class `parallel` has the wrong name.
-// }
+ // NOTE: can't mark as thread-safe here, because unpickleClass might decide to delegate to FromJavaClassCompleter
+ // if (!isCompilerUniverse) markAllCompleted(clazz, module)
}
}
override def load(sym: Symbol) = complete(sym)
@@ -58,7 +39,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
* @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) = {
+ protected def initAndEnterClassAndModule(owner: Symbol, name: TypeName, completer: (Symbol, Symbol) => LazyType) = {
assert(!(name.toString endsWith "[]"), name)
val clazz = owner.newClass(name)
val module = owner.newModule(name.toTermName)
@@ -68,7 +49,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
owner.info.decls enter clazz
owner.info.decls enter module
}
- initClassModule(clazz, module, completer(clazz, module))
+ initClassAndModule(clazz, module, completer(clazz, module))
(clazz, module)
}
@@ -76,7 +57,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
List(clazz, module, module.moduleClass) foreach (_ setInfo info)
}
- protected def initClassModule(clazz: Symbol, module: Symbol, completer: LazyType) =
+ protected def initClassAndModule(clazz: Symbol, module: Symbol, completer: LazyType) =
setAllInfos(clazz, module, completer)
/** The type completer for packages.
@@ -87,15 +68,56 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
sym setInfo new ClassInfoType(List(), new PackageScope(sym), sym)
// override def safeToString = pkgClass.toString
openPackageModule(sym)
+ markAllCompleted(sym)
}
}
- class PackageScope(pkgClass: Symbol) extends Scope(initFingerPrints = -1L) // disable fingerprinting as we do not know entries beforehand
+
+ // Since runtime reflection doesn't have a luxury of enumerating all classes
+ // on the classpath, it has to materialize symbols for top-level definitions
+ // (packages, classes, objects) on demand.
+ //
+ // Someone asks us for a class named `foo.Bar`? Easy. Let's speculatively create
+ // a package named `foo` and then look up `newTypeName("bar")` in its decls.
+ // This lookup, implemented in `SymbolLoaders.PackageScope` tests the waters by
+ // trying to to `Class.forName("foo.Bar")` and then creates a ClassSymbol upon
+ // success (the whole story is a bit longer, but the rest is irrelevant here).
+ //
+ // That's all neat, but these non-deterministic mutations of the global symbol
+ // table give a lot of trouble in multi-threaded setting. One of the popular
+ // reflection crashes happens when multiple threads happen to trigger symbol
+ // materialization multiple times for the same symbol, making subsequent
+ // reflective operations stumble upon outrageous stuff like overloaded packages.
+ //
+ // Short of significantly changing SymbolLoaders I see no other way than just
+ // to slap a global lock on materialization in runtime reflection.
+ class PackageScope(pkgClass: Symbol) extends Scope
with SynchronizedScope {
assert(pkgClass.isType)
- // disable fingerprinting as we do not know entries beforehand
- private val negatives = mutable.Set[Name]() // Syncnote: Performance only, so need not be protected.
- override def lookupEntry(name: Name): ScopeEntry = {
+
+ // materializing multiple copies of the same symbol in PackageScope is a very popular bug
+ // this override does its best to guard against it
+ override def enter[T <: Symbol](sym: T): T = {
+ // workaround for SI-7728
+ if (isCompilerUniverse) super.enter(sym)
+ else {
+ val existing = super.lookupEntry(sym.name)
+ assert(existing == null || existing.sym.isMethod, s"pkgClass = $pkgClass, sym = $sym, existing = $existing")
+ super.enter(sym)
+ }
+ }
+
+ override def enterIfNew[T <: Symbol](sym: T): T = {
+ val existing = super.lookupEntry(sym.name)
+ if (existing == null) enter(sym)
+ else existing.sym.asInstanceOf[T]
+ }
+
+ // package scopes need to synchronize on the GIL
+ // because lookupEntry might cause changes to the global symbol table
+ override def syncLockSynchronized[T](body: => T): T = gilSynchronized(body)
+ private val negatives = new mutable.HashSet[Name]
+ override def lookupEntry(name: Name): ScopeEntry = syncLockSynchronized {
val e = super.lookupEntry(name)
if (e != null)
e
@@ -109,17 +131,30 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
currentMirror.tryJavaClass(path) match {
case Some(cls) =>
val loadingMirror = currentMirror.mirrorDefining(cls)
- val (clazz, module) =
+ val (_, module) =
if (loadingMirror eq currentMirror) {
- createClassModule(pkgClass, name.toTypeName, new TopClassCompleter(_, _))
+ initAndEnterClassAndModule(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
+ // currentMirror.mirrorDefining(cls) might side effect by entering symbols into pkgClass.info.decls
+ // therefore, even though in the beginning of this method, super.lookupEntry(name) returned null
+ // entering clazz/module now will result in a double-enter assertion in PackageScope.enter
+ // here's how it might happen
+ // 1) we are the rootMirror
+ // 2) cls.getClassLoader is different from our classloader
+ // 3) mirrorDefining(cls) looks up a mirror corresponding to that classloader and cannot find it
+ // 4) mirrorDefining creates a new mirror
+ // 5) that triggers Mirror.init() of the new mirror
+ // 6) that triggers definitions.syntheticCoreClasses
+ // 7) that might materialize symbols and enter them into our scope (because syntheticCoreClasses live in rootMirror)
+ // 8) now we come back here and try to enter one of the now entered symbols => BAM!
+ // therefore we use enterIfNew rather than just enter
+ enterIfNew(clazz)
+ enterIfNew(module)
(clazz, module)
}
debugInfo(s"created $module/${module.moduleClass} in $pkgClass")
diff --git a/src/reflect/scala/reflect/runtime/SymbolTable.scala b/src/reflect/scala/reflect/runtime/SymbolTable.scala
index 5c08e9a508..02155578f8 100644
--- a/src/reflect/scala/reflect/runtime/SymbolTable.scala
+++ b/src/reflect/scala/reflect/runtime/SymbolTable.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package runtime
import scala.reflect.internal.Flags._
@@ -8,13 +9,13 @@ import scala.reflect.internal.Flags._
* It can be used either from a reflexive universe (class scala.reflect.runtime.JavaUniverse), or else from
* a runtime compiler that uses reflection to get a class information (class scala.tools.reflect.ReflectGlobal)
*/
-private[scala] trait SymbolTable extends internal.SymbolTable with JavaMirrors with SymbolLoaders with SynchronizedOps {
+private[scala] trait SymbolTable extends internal.SymbolTable with JavaMirrors with SymbolLoaders with SynchronizedOps with Gil with ThreadLocalStorage {
def info(msg: => String) =
- if (settings.verbose.value) println("[reflect-compiler] "+msg)
+ if (settings.verbose) println("[reflect-compiler] "+msg)
def debugInfo(msg: => String) =
- if (settings.debug.value) info(msg)
+ if (settings.debug) info(msg)
/** Declares that this is a runtime reflection universe.
*
@@ -27,19 +28,4 @@ private[scala] trait SymbolTable extends internal.SymbolTable with JavaMirrors w
* in order to prevent memory leaks: http://groups.google.com/group/scala-internals/browse_thread/thread/eabcf3d406dab8b2.
*/
override def isCompilerUniverse = false
-
- /** Unlike compiler universes, reflective universes can auto-initialize symbols on flag requests.
- *
- * scalac wasn't designed with such auto-initialization in mind, and quite often it makes assumptions
- * that flag requests won't cause initialization. Therefore enabling auto-init leads to cyclic errors.
- * We could probably fix those, but at the moment it's too risky.
- *
- * Reflective universes share codebase with scalac, but their surface is much smaller, which means less assumptions.
- * These assumptions are taken care of in this overriden `shouldTriggerCompleter` method.
- */
- override protected def shouldTriggerCompleter(symbol: Symbol, completer: Type, isFlagRelated: Boolean, mask: Long) =
- completer match {
- case _: TopClassCompleter | _: JavaClassCompleter => !isFlagRelated || (mask & TopLevelPickledFlags) != 0
- case _ => super.shouldTriggerCompleter(symbol, completer, isFlagRelated, mask)
- }
}
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
index 7b280e59b9..4a8585d616 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package runtime
// SI-6240: test thread-safety, make trees synchronized as well
@@ -8,45 +9,50 @@ private[reflect] trait SynchronizedOps extends internal.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) }
+ override protected def synchronizeNames = true
// BaseTypeSeqs
override protected def newBaseTypeSeq(parents: List[Type], elems: Array[Type]) =
- new BaseTypeSeq(parents, elems) with SynchronizedBaseTypeSeq
+ // only need to synchronize BaseTypeSeqs if they contain refined types
+ if (elems.filter(_.isInstanceOf[RefinedType]).nonEmpty) new BaseTypeSeq(parents, elems) with SynchronizedBaseTypeSeq
+ else new BaseTypeSeq(parents, elems)
trait SynchronizedBaseTypeSeq extends BaseTypeSeq {
- override def apply(i: Int): Type = synchronized { super.apply(i) }
- override def rawElem(i: Int) = synchronized { super.rawElem(i) }
- override def typeSymbol(i: Int): Symbol = synchronized { super.typeSymbol(i) }
- override def toList: List[Type] = synchronized { super.toList }
- override def copy(head: Type, offset: Int): BaseTypeSeq = synchronized { super.copy(head, offset) }
- override def map(f: Type => Type): BaseTypeSeq = synchronized { super.map(f) }
- override def exists(p: Type => Boolean): Boolean = synchronized { super.exists(p) }
- override lazy val maxDepth = synchronized { maxDepthOfElems }
- override def toString = synchronized { super.toString }
-
- override def lateMap(f: Type => Type): BaseTypeSeq = new MappedBaseTypeSeq(this, f) with SynchronizedBaseTypeSeq
+ override def apply(i: Int): Type = gilSynchronized { super.apply(i) }
+ override def rawElem(i: Int) = gilSynchronized { super.rawElem(i) }
+ override def typeSymbol(i: Int): Symbol = gilSynchronized { super.typeSymbol(i) }
+ override def toList: List[Type] = gilSynchronized { super.toList }
+ override def copy(head: Type, offset: Int): BaseTypeSeq = gilSynchronized { super.copy(head, offset) }
+ override def map(f: Type => Type): BaseTypeSeq = gilSynchronized { super.map(f) }
+ override def exists(p: Type => Boolean): Boolean = gilSynchronized { super.exists(p) }
+ override lazy val maxDepth = gilSynchronized { maxDepthOfElems }
+ override def toString = gilSynchronized { super.toString }
+
+ override def lateMap(f: Type => Type): BaseTypeSeq =
+ // only need to synchronize BaseTypeSeqs if they contain refined types
+ if (map(f).toList.filter(_.isInstanceOf[RefinedType]).nonEmpty) new MappedBaseTypeSeq(this, f) with SynchronizedBaseTypeSeq
+ else new MappedBaseTypeSeq(this, f)
}
// Scopes
- override def newScope = new Scope() with SynchronizedScope
- override def newNestedScope(outer: Scope): Scope = new Scope(outer) with SynchronizedScope
+ override def newScope = new Scope with SynchronizedScope
trait SynchronizedScope extends Scope {
- override def isEmpty: Boolean = synchronized { super.isEmpty }
- override def size: Int = synchronized { super.size }
- override def enter[T <: Symbol](sym: T): T = synchronized { super.enter(sym) }
- override def rehash(sym: Symbol, newname: Name) = synchronized { super.rehash(sym, newname) }
- override def unlink(e: ScopeEntry) = synchronized { super.unlink(e) }
- override def unlink(sym: Symbol) = synchronized { super.unlink(sym) }
- override def lookupAll(name: Name) = synchronized { super.lookupAll(name) }
- override def lookupEntry(name: Name) = synchronized { super.lookupEntry(name) }
- override def lookupNextEntry(entry: ScopeEntry) = synchronized { super.lookupNextEntry(entry) }
- override def toList: List[Symbol] = synchronized { super.toList }
+ // we can keep this lock fine-grained, because methods of Scope don't do anything extraordinary, which makes deadlocks impossible
+ // fancy subclasses of internal.Scopes#Scope should do synchronization themselves (e.g. see PackageScope for an example)
+ private lazy val syncLock = new Object
+ def syncLockSynchronized[T](body: => T): T = if (isCompilerUniverse) body else syncLock.synchronized { body }
+ override def isEmpty: Boolean = syncLockSynchronized { super.isEmpty }
+ override def size: Int = syncLockSynchronized { super.size }
+ override def enter[T <: Symbol](sym: T): T = syncLockSynchronized { super.enter(sym) }
+ override def rehash(sym: Symbol, newname: Name) = syncLockSynchronized { super.rehash(sym, newname) }
+ override def unlink(e: ScopeEntry) = syncLockSynchronized { super.unlink(e) }
+ override def unlink(sym: Symbol) = syncLockSynchronized { super.unlink(sym) }
+ override def lookupAll(name: Name) = syncLockSynchronized { super.lookupAll(name) }
+ override def lookupEntry(name: Name) = syncLockSynchronized { super.lookupEntry(name) }
+ override def lookupNextEntry(entry: ScopeEntry) = syncLockSynchronized { super.lookupNextEntry(entry) }
+ override def toList: List[Symbol] = syncLockSynchronized { super.toList }
}
}
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
index 00f6952dc1..f5e16c6640 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
@@ -1,18 +1,26 @@
-package scala.reflect
+package scala
+package reflect
package runtime
import scala.reflect.io.AbstractFile
+import scala.collection.{ immutable, mutable }
+import scala.reflect.internal.Flags._
private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable =>
- override protected def nextId() = synchronized { super.nextId() }
+ private lazy val atomicIds = new java.util.concurrent.atomic.AtomicInteger(0)
+ override protected def nextId() = atomicIds.incrementAndGet()
- override protected def freshExistentialName(suffix: String) =
- synchronized { super.freshExistentialName(suffix) }
+ private lazy val atomicExistentialIds = new java.util.concurrent.atomic.AtomicInteger(0)
+ override protected def nextExistentialId() = atomicExistentialIds.incrementAndGet()
+
+ private lazy val _recursionTable = mkThreadLocalStorage(immutable.Map.empty[Symbol, Int])
+ override def recursionTable = _recursionTable.get
+ override def recursionTable_=(value: immutable.Map[Symbol, Int]) = _recursionTable.set(value)
// Set the fields which point companions at one another. Returns the module.
override def connectModuleToClass(m: ModuleSymbol, moduleClass: ClassSymbol): ModuleSymbol =
- synchronized { super.connectModuleToClass(m, moduleClass) }
+ gilSynchronized { super.connectModuleToClass(m, moduleClass) }
override def newFreeTermSymbol(name: TermName, value: => Any, flags: Long = 0L, origin: String = null): FreeTermSymbol =
new FreeTermSymbol(name, value, origin) with SynchronizedTermSymbol initFlags flags
@@ -24,35 +32,127 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb
trait SynchronizedSymbol extends Symbol {
- override def rawflags = synchronized { super.rawflags }
- override def rawflags_=(x: Long) = synchronized { super.rawflags_=(x) }
-
- override def rawowner = synchronized { super.rawowner }
- override def owner_=(owner: Symbol) = synchronized { super.owner_=(owner) }
-
- override def validTo = synchronized { super.validTo }
- override def validTo_=(x: Period) = synchronized { super.validTo_=(x) }
-
- override def pos = synchronized { super.pos }
- override def setPos(pos: Position): this.type = { synchronized { super.setPos(pos) }; this }
-
- override def privateWithin = synchronized { super.privateWithin }
- override def privateWithin_=(sym: Symbol) = synchronized { super.privateWithin_=(sym) }
-
- override def info = synchronized { super.info }
- override def info_=(info: Type) = synchronized { super.info_=(info) }
- override def updateInfo(info: Type): Symbol = synchronized { super.updateInfo(info) }
- override def rawInfo: Type = synchronized { super.rawInfo }
-
- override def typeParams: List[Symbol] = synchronized { super.typeParams }
-
- override def reset(completer: Type): this.type = synchronized { super.reset(completer) }
-
- override def infosString: String = synchronized { super.infosString }
-
- override def annotations: List[AnnotationInfo] = synchronized { super.annotations }
- override def setAnnotations(annots: List[AnnotationInfo]): this.type = { synchronized { super.setAnnotations(annots) }; this }
-
+ /** (Things written in this comment only applies to runtime reflection. Compile-time reflection,
+ * especially across phases and runs, is somewhat more complicated, but we won't be touching it,
+ * because at the moment we only care about synchronizing runtime reflection).
+ *
+ * As it has been noted on multiple occasions, generally speaking, reflection artifacts aren't thread-safe.
+ * Reasons for that differ from artifact to artifact. In some cases it's quite bad (e.g. types use a number
+ * of non-concurrent compiler caches, so we need to serialize certain operations on types in order to make
+ * sure that things stay deterministic). However, in case of symbols there's hope, because it's only during
+ * initializaton that symbols are thread-unsafe. After everything's set up, symbols become immutable
+ * (sans a few deterministic caches that can be populated simultaneously by multiple threads) and therefore thread-safe.
+ *
+ * Note that by saying "symbols become immutable" I mean literally that. In a very common case of PackageClassSymbol's,
+ * even when a symbol finishes its initialization and becomes immutable, its info forever remains mutable.
+ * Therefore even if we no longer need to synchronize a PackageClassSymbol after it's initialized, we still have to take
+ * care of its ClassInfoType (or, more precisely, of the underlying Scope), but that's done elsewhere, and
+ * here we don't need to worry about that.
+ *
+ * Okay, so now we simply check `Symbol.isInitialized` and if it's true, then everything's fine? Haha, nope!
+ * The thing is that some completers call sym.setInfo when still in-flight and then proceed with initialization
+ * (e.g. see LazyPackageType). Consequently, setInfo sets _validTo to current period, which means that after
+ * a call to setInfo isInitialized will start returning true. Unfortunately, this doesn't mean that info becomes
+ * ready to be used, because subsequent initialization might change the info.
+ *
+ * Therefore we need to somehow distinguish between initialized and really initialized symbol states.
+ * Okay, let's do it on per-completer basis. We have seven kinds of completers to worry about:
+ * 1) LazyPackageType that initializes packages and their underlying package classes
+ * 2) TopClassCompleter that initializes top-level Scala-based class-module companion pairs of static definitions
+ * 3) LazyTypeRef and LazyTypeRefAndAlias set up by TopClassCompleter that initialize (transitive members) of top-level classes/modules
+ * 4) FromJavaClassCompleter that does the same for both top-level and non-toplevel Java-based classes/modules
+ * 5) Fully-initialized signatures of non-class/module Java-based reflection artifacts
+ * 6) Importing completer that transfers metadata from one universe to another
+ * 7) Signatures of special symbols such as roots and symbolsNotPresentInBytecode
+ *
+ * The mechanisms underlying completion are quite complex, and it'd be only natural to suppose that over time we're going to overlook something.
+ * Wrt isThreadsafe we could have two wrong situations: false positives (isThreadsafe = true, but the symbol isn't actually threadsafe)
+ * and false negatives (isThreadsafe = false, but the symbol is actually threadsafe). However, even though both are wrong, only the former
+ * is actively malicious. Indeed, false positives might lead to races, inconsistent state and crashes, while the latter would only cause
+ * `initialize` to be called and a gil to be taken on every potentially auto-initializable operation. Unpleasant yes, but still robust.
+ *
+ * What makes me hopeful is that:
+ * 1) By default (e.g. if some new completion mechanism gets introduced for a special flavor of symbols and we forget to call markCompleted)
+ * isThreadsafe is always in false negative state, which is unpleasant but safe.
+ * 2) Calls to `markCompleted` which are the only potential source of erroneous behavior are few and are relatively easy to place:
+ * just put them just before your completer's `complete` returns, and you should be fine.
+ *
+ * upd. Actually, there's another problem of not keeping initialization mask up-to-date. If we're not careful enough,
+ * then it might so happen that getting a certain flag that the compiler assumes to be definitively set will spuriously
+ * return isThreadsafe(purpose = FlagsOp(<flag>)) = false and that will lead to spurious auto-initialization,
+ * which will cause an SO or a cyclic reference or some other crash. I've done my best to go through all possible completers
+ * and call `markFlagsCompleted` where appropriate, but again over time something might be overlooked, so to guard against that
+ * I'm only considering TopLevelPickledFlags to be sources of potential initialization. This ensures that such system flags as
+ * isMethod, isModule or isPackage are never going to auto-initialize.
+ */
+ override def isThreadsafe(purpose: SymbolOps) = {
+ if (isCompilerUniverse) false
+ else if (_initialized) true
+ else purpose.isFlagRelated && (_initializationMask & purpose.mask & TopLevelPickledFlags) == 0
+ }
+
+ /** Communicates with completers declared in scala.reflect.runtime.SymbolLoaders
+ * about the status of initialization of the underlying symbol.
+ *
+ * Unfortunately, it's not as easy as just introducing the `markThreadsafe` method that would be called
+ * by the completers when they are really done (as opposed to `setInfo` that, as mentioned above, doesn't mean anything).
+ *
+ * Since we also want to auto-initialize symbols when certain methods are being called (`Symbol.hasFlag` for example),
+ * we need to track the identity of the initializer, so as to block until initialization is complete if the caller
+ * comes from a different thread, but to skip auto-initialization if we're the initializing thread.
+ *
+ * Just a volatile var is fine, because:
+ * 1) Status can only be changed in a single-threaded fashion (this is enforced by gilSynchronized
+ * that effecively guards `Symbol.initialize`), which means that there can't be update conflicts.
+ * 2) If someone reads a stale value of status, then the worst thing that might happen is that this someone
+ * is going to spuriously call `initialize`, which is either a gil-protected operation (if the symbol isn't inited yet)
+ * or a no-op (if the symbol is already inited), and that is fine in both cases.
+ *
+ * upd. It looks like we also need to keep track of a mask of initialized flags to make sure
+ * that normal symbol initialization routines don't trigger auto-init in Symbol.flags-related routines (e.g. Symbol.getFlag).
+ * Due to the same reasoning as above, a single volatile var is enough for to store the mask.
+ */
+ @volatile private[this] var _initialized = false
+ @volatile private[this] var _initializationMask = TopLevelPickledFlags
+ override def markFlagsCompleted(mask: Long): this.type = { _initializationMask = _initializationMask & ~mask; this }
+ override def markAllCompleted(): this.type = { _initializationMask = 0L; _initialized = true; this }
+
+ def gilSynchronizedIfNotThreadsafe[T](body: => T): T = {
+ // TODO: debug and fix the race that doesn't allow us uncomment this optimization
+ // if (isCompilerUniverse || isThreadsafe(purpose = AllOps)) body
+ // else gilSynchronized { body }
+ gilSynchronized { body }
+ }
+
+ override def validTo = gilSynchronizedIfNotThreadsafe { super.validTo }
+ override def info = gilSynchronizedIfNotThreadsafe { super.info }
+ override def rawInfo: Type = gilSynchronizedIfNotThreadsafe { super.rawInfo }
+ override def typeSignature: Type = gilSynchronizedIfNotThreadsafe { super.typeSignature }
+ override def typeSignatureIn(site: Type): Type = gilSynchronizedIfNotThreadsafe { super.typeSignatureIn(site) }
+
+ override def typeParams: List[Symbol] = gilSynchronizedIfNotThreadsafe {
+ if (isCompilerUniverse) super.typeParams
+ else {
+ if (isMonomorphicType) Nil
+ else {
+ // analogously to the "info" getter, here we allow for two completions:
+ // one: sourceCompleter to LazyType, two: LazyType to completed type
+ if (validTo == NoPeriod)
+ rawInfo load this
+ if (validTo == NoPeriod)
+ rawInfo load this
+
+ rawInfo.typeParams
+ }
+ }
+ }
+ override def unsafeTypeParams: List[Symbol] = gilSynchronizedIfNotThreadsafe {
+ if (isCompilerUniverse) super.unsafeTypeParams
+ else {
+ if (isMonomorphicType) Nil
+ else rawInfo.typeParams
+ }
+ }
// ------ creators -------------------------------------------------------------------
@@ -83,58 +183,44 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb
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)
+ override protected def createPackageSymbol(name: TermName, pos: Position, newFlags: Long): ModuleSymbol =
+ createModuleSymbol(name, pos, newFlags)
+
+ override protected def createValueParameterSymbol(name: TermName, pos: Position, newFlags: Long) =
+ new TermSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags
- // TODO
- // override protected def createValueParameterSymbol(name: TermName, pos: Position, newFlags: Long)
- // override protected def createValueMemberSymbol(name: TermName, pos: Position, newFlags: Long)
+ override protected def createValueMemberSymbol(name: TermName, pos: Position, newFlags: Long) =
+ new TermSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags
}
// ------- subclasses ---------------------------------------------------------------------
- trait SynchronizedTermSymbol extends TermSymbol with SynchronizedSymbol {
- override def name_=(x: Name) = synchronized { super.name_=(x) }
- override def rawname = synchronized { super.rawname }
- override def referenced: Symbol = synchronized { super.referenced }
- override def referenced_=(x: Symbol) = synchronized { super.referenced_=(x) }
- }
+ trait SynchronizedTermSymbol extends SynchronizedSymbol
trait SynchronizedMethodSymbol extends MethodSymbol with SynchronizedTermSymbol {
- override def typeAsMemberOf(pre: Type): Type = synchronized { super.typeAsMemberOf(pre) }
- override def paramss: List[List[Symbol]] = synchronized { super.paramss }
- override def returnType: Type = synchronized { super.returnType }
+ // we can keep this lock fine-grained, because it's just a cache over asSeenFrom, which makes deadlocks impossible
+ // unfortunately we cannot elide this lock, because the cache depends on `pre`
+ private lazy val typeAsMemberOfLock = new Object
+ override def typeAsMemberOf(pre: Type): Type = gilSynchronizedIfNotThreadsafe { typeAsMemberOfLock.synchronized { super.typeAsMemberOf(pre) } }
}
+ trait SynchronizedModuleSymbol extends ModuleSymbol with SynchronizedTermSymbol
+
trait SynchronizedTypeSymbol extends TypeSymbol with SynchronizedSymbol {
- override def name_=(x: Name) = synchronized { super.name_=(x) }
- override def rawname = synchronized { super.rawname }
- override def typeConstructor: Type = synchronized { super.typeConstructor }
- override def tpe: Type = synchronized { super.tpe }
+ // unlike with typeConstructor, a lock is necessary here, because tpe calculation relies on
+ // temporarily assigning NoType to tpeCache to detect cyclic reference errors
+ private lazy val tpeLock = new Object
+ override def tpe_* : Type = gilSynchronizedIfNotThreadsafe { tpeLock.synchronized { super.tpe_* } }
}
- trait SynchronizedClassSymbol extends ClassSymbol with SynchronizedTypeSymbol {
- override def associatedFile = synchronized { super.associatedFile }
- override def associatedFile_=(f: AbstractFile) = synchronized { super.associatedFile_=(f) }
- override def thisSym: Symbol = synchronized { super.thisSym }
- override def thisType: Type = synchronized { super.thisType }
- override def typeOfThis: Type = synchronized { super.typeOfThis }
- override def typeOfThis_=(tp: Type) = synchronized { super.typeOfThis_=(tp) }
- override def children = synchronized { super.children }
- override def addChild(sym: Symbol) = synchronized { super.addChild(sym) }
- }
+ trait SynchronizedClassSymbol extends ClassSymbol with SynchronizedTypeSymbol
- trait SynchronizedModuleClassSymbol extends ModuleClassSymbol with SynchronizedClassSymbol {
- override def sourceModule = synchronized { super.sourceModule }
- override def implicitMembers: Scope = synchronized { super.implicitMembers }
- }
+ trait SynchronizedModuleClassSymbol extends ModuleClassSymbol with SynchronizedClassSymbol
}
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
index a3e7c28ca4..9bcf85dd6f 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
@@ -1,8 +1,11 @@
-package scala.reflect
+package scala
+package reflect
package runtime
-import scala.collection.mutable.WeakHashMap
-import java.lang.ref.WeakReference
+import scala.collection.mutable
+import java.lang.ref.{WeakReference => jWeakRef}
+import scala.ref.{WeakReference => sWeakRef}
+import scala.reflect.internal.Depth
/** This trait overrides methods in reflect.internal, bracketing
* them in synchronized { ... } to make them thread-safe
@@ -12,9 +15,10 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa
// No sharing of map objects:
override protected def commonOwnerMap = new CommonOwnerMap
- private object uniqueLock
-
- private val uniques = WeakHashMap[Type, WeakReference[Type]]()
+ // we can keep this lock fine-grained, because super.unique just updates the cache
+ // and, in particular, doesn't call any reflection APIs which makes deadlocks impossible
+ private lazy val uniqueLock = new Object
+ private val uniques = mutable.WeakHashMap[Type, jWeakRef[Type]]()
override def unique[T <: Type](tp: T): T = uniqueLock.synchronized {
// we need to have weak uniques for runtime reflection
// because unlike the normal compiler universe, reflective universe isn't organized in runs
@@ -28,7 +32,7 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa
val result = if (inCache.isDefined) inCache.get.get else null
if (result ne null) result.asInstanceOf[T]
else {
- uniques(tp) = new WeakReference(tp)
+ uniques(tp) = new jWeakRef(tp)
tp
}
} else {
@@ -36,47 +40,46 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa
}
}
- class SynchronizedUndoLog extends UndoLog {
- private val actualLock = new java.util.concurrent.locks.ReentrantLock
-
- final override def lock(): Unit = actualLock.lock()
- final override def unlock(): Unit = actualLock.unlock()
- }
-
- override protected def newUndoLog = new SynchronizedUndoLog
-
- override protected def baseTypeOfNonClassTypeRef(tpe: NonClassTypeRef, clazz: Symbol) =
- synchronized { super.baseTypeOfNonClassTypeRef(tpe, clazz) }
+ private lazy val _skolemizationLevel = mkThreadLocalStorage(0)
+ override def skolemizationLevel = _skolemizationLevel.get
+ override def skolemizationLevel_=(value: Int) = _skolemizationLevel.set(value)
- private object subsametypeLock
+ private lazy val _undoLog = mkThreadLocalStorage(new UndoLog)
+ override def undoLog = _undoLog.get
- override def isSameType(tp1: Type, tp2: Type): Boolean =
- subsametypeLock.synchronized { super.isSameType(tp1, tp2) }
+ private lazy val _intersectionWitness = mkThreadLocalStorage(perRunCaches.newWeakMap[List[Type], sWeakRef[Type]]())
+ override def intersectionWitness = _intersectionWitness.get
- override def isDifferentType(tp1: Type, tp2: Type): Boolean =
- subsametypeLock.synchronized { super.isDifferentType(tp1, tp2) }
+ private lazy val _subsametypeRecursions = mkThreadLocalStorage(0)
+ override def subsametypeRecursions = _subsametypeRecursions.get
+ override def subsametypeRecursions_=(value: Int) = _subsametypeRecursions.set(value)
- override def isSubType(tp1: Type, tp2: Type, depth: Int): Boolean =
- subsametypeLock.synchronized { super.isSubType(tp1, tp2, depth) }
+ private lazy val _pendingSubTypes = mkThreadLocalStorage(new mutable.HashSet[SubTypePair])
+ override def pendingSubTypes = _pendingSubTypes.get
- private object lubglbLock
+ private lazy val _basetypeRecursions = mkThreadLocalStorage(0)
+ override def basetypeRecursions = _basetypeRecursions.get
+ override def basetypeRecursions_=(value: Int) = _basetypeRecursions.set(value)
- override def glb(ts: List[Type]): Type =
- lubglbLock.synchronized { super.glb(ts) }
+ private lazy val _pendingBaseTypes = mkThreadLocalStorage(new mutable.HashSet[Type])
+ override def pendingBaseTypes = _pendingBaseTypes.get
- override def lub(ts: List[Type]): Type =
- lubglbLock.synchronized { super.lub(ts) }
+ private lazy val _lubResults = mkThreadLocalStorage(new mutable.HashMap[(Depth, List[Type]), Type])
+ override def lubResults = _lubResults.get
- private object indentLock
+ private lazy val _glbResults = mkThreadLocalStorage(new mutable.HashMap[(Depth, List[Type]), Type])
+ override def glbResults = _glbResults.get
- override protected def explain[T](op: String, p: (Type, T) => Boolean, tp1: Type, arg2: T): Boolean = {
- indentLock.synchronized { super.explain(op, p, tp1, arg2) }
- }
+ private lazy val _indent = mkThreadLocalStorage("")
+ override def indent = _indent.get
+ override def indent_=(value: String) = _indent.set(value)
- private object toStringLock
+ private lazy val _toStringRecursions = mkThreadLocalStorage(0)
+ override def toStringRecursions = _toStringRecursions.get
+ override def toStringRecursions_=(value: Int) = _toStringRecursions.set(value)
- override protected def typeToString(tpe: Type): String =
- toStringLock.synchronized(super.typeToString(tpe))
+ private lazy val _toStringSubjects = mkThreadLocalStorage(new mutable.HashSet[Type])
+ override def toStringSubjects = _toStringSubjects.get
/* The idea of caches is as follows.
* When in reflexive mode, a cache is either null, or one sentinal
@@ -89,18 +92,18 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa
*/
override protected def defineUnderlyingOfSingleType(tpe: SingleType) =
- tpe.synchronized { super.defineUnderlyingOfSingleType(tpe) }
+ gilSynchronized { super.defineUnderlyingOfSingleType(tpe) }
override protected def defineBaseTypeSeqOfCompoundType(tpe: CompoundType) =
- tpe.synchronized { super.defineBaseTypeSeqOfCompoundType(tpe) }
+ gilSynchronized { super.defineBaseTypeSeqOfCompoundType(tpe) }
override protected def defineBaseClassesOfCompoundType(tpe: CompoundType) =
- tpe.synchronized { super.defineBaseClassesOfCompoundType(tpe) }
+ gilSynchronized { super.defineBaseClassesOfCompoundType(tpe) }
override protected def defineParentsOfTypeRef(tpe: TypeRef) =
- tpe.synchronized { super.defineParentsOfTypeRef(tpe) }
+ gilSynchronized { super.defineParentsOfTypeRef(tpe) }
override protected def defineBaseTypeSeqOfTypeRef(tpe: TypeRef) =
- tpe.synchronized { super.defineBaseTypeSeqOfTypeRef(tpe) }
+ gilSynchronized { super.defineBaseTypeSeqOfTypeRef(tpe) }
}
diff --git a/src/reflect/scala/reflect/runtime/ThreadLocalStorage.scala b/src/reflect/scala/reflect/runtime/ThreadLocalStorage.scala
new file mode 100644
index 0000000000..5edc051461
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/ThreadLocalStorage.scala
@@ -0,0 +1,28 @@
+package scala.reflect
+package runtime
+
+import java.lang.Thread._
+
+private[reflect] trait ThreadLocalStorage {
+ self: SymbolTable =>
+
+ // see a discussion at scala-internals for more information:
+ // http://groups.google.com/group/scala-internals/browse_thread/thread/337ce68aa5e51f79
+ trait ThreadLocalStorage[T] { def get: T; def set(newValue: T): Unit }
+ private class MyThreadLocalStorage[T](initialValue: => T) extends ThreadLocalStorage[T] {
+ // TODO: how do we use org.cliffc.high_scale_lib.NonBlockingHashMap here?
+ val values = new java.util.concurrent.ConcurrentHashMap[Thread, T]()
+ def get: T = {
+ if (values containsKey currentThread) values.get(currentThread)
+ else {
+ val value = initialValue
+ values.putIfAbsent(currentThread, value)
+ value
+ }
+ }
+ def set(newValue: T): Unit = {
+ values.put(currentThread, newValue)
+ }
+ }
+ @inline final def mkThreadLocalStorage[T](x: => T): ThreadLocalStorage[T] = new MyThreadLocalStorage(x)
+}
diff --git a/src/reflect/scala/reflect/runtime/TwoWayCache.scala b/src/reflect/scala/reflect/runtime/TwoWayCache.scala
index 05debcba65..d0fc3dac74 100644
--- a/src/reflect/scala/reflect/runtime/TwoWayCache.scala
+++ b/src/reflect/scala/reflect/runtime/TwoWayCache.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
package runtime
import scala.collection.mutable.WeakHashMap
@@ -51,16 +52,4 @@ private[runtime] class TwoWayCache[J, S] {
result
}
}
-
- def toJavaOption(key: S)(body: => Option[J]): Option[J] = synchronized {
- toJavaMap get key match {
- case SomeRef(v) =>
- Some(v)
- case _ =>
- val result = body
- for (value <- result) enter(value, key)
- result
- }
- }
}
-
diff --git a/src/reflect/scala/reflect/runtime/TwoWayCaches.scala b/src/reflect/scala/reflect/runtime/TwoWayCaches.scala
new file mode 100644
index 0000000000..6e2890e536
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/TwoWayCaches.scala
@@ -0,0 +1,68 @@
+package scala.reflect
+package runtime
+
+import scala.collection.mutable.WeakHashMap
+import java.lang.ref.WeakReference
+
+/** A cache that maintains a bijection between Java reflection type `J`
+ * and Scala reflection type `S`.
+ *
+ * The cache is two-way weak (i.e. is powered by weak references),
+ * so that neither Java artifacts prevent Scala artifacts from being garbage collected,
+ * nor the other way around.
+ */
+private[runtime] trait TwoWayCaches { self: SymbolTable =>
+ class TwoWayCache[J, S] {
+
+ private val toScalaMap = new WeakHashMap[J, WeakReference[S]]
+ private val toJavaMap = new WeakHashMap[S, WeakReference[J]]
+
+ def enter(j: J, s: S) = gilSynchronized {
+ // debugInfo("cached: "+j+"/"+s)
+ toScalaMap(j) = new WeakReference(s)
+ toJavaMap(s) = new WeakReference(j)
+ }
+
+ private object SomeRef {
+ def unapply[T](optRef: Option[WeakReference[T]]): Option[T] =
+ if (optRef.nonEmpty) {
+ val result = optRef.get.get
+ if (result != null) Some(result) else None
+ } else None
+ }
+
+ def toScala(key: J)(body: => S): S = gilSynchronized {
+ toScalaMap get key match {
+ case SomeRef(v) =>
+ v
+ case _ =>
+ val result = body
+ enter(key, result)
+ result
+ }
+ }
+
+ def toJava(key: S)(body: => J): J = gilSynchronized {
+ toJavaMap get key match {
+ case SomeRef(v) =>
+ v
+ case _ =>
+ val result = body
+ enter(result, key)
+ result
+ }
+ }
+
+ def toJavaOption(key: S)(body: => Option[J]): Option[J] = gilSynchronized {
+ toJavaMap get key match {
+ case SomeRef(v) =>
+ Some(v)
+ case _ =>
+ val result = body
+ for (value <- result) enter(value, key)
+ result
+ }
+ }
+ }
+}
+
diff --git a/src/reflect/scala/reflect/runtime/package.scala b/src/reflect/scala/reflect/runtime/package.scala
index b97913daf0..e240bed0a7 100644
--- a/src/reflect/scala/reflect/runtime/package.scala
+++ b/src/reflect/scala/reflect/runtime/package.scala
@@ -1,4 +1,5 @@
-package scala.reflect
+package scala
+package reflect
/** Entry points into runtime reflection.
* See [[scala.reflect.api.package the overview page]] for details on how to use them.
@@ -6,7 +7,7 @@ package scala.reflect
package object runtime {
/** The entry point into Scala runtime reflection.
- *
+ *
* To use Scala runtime reflection, simply use or import `scala.reflect.runtime.universe._`
*
* See [[scala.reflect.api.Universe]] or the
@@ -20,16 +21,17 @@ package object runtime {
*/
// implementation hardwired to the `currentMirror` method below
// using the mechanism implemented in `scala.tools.reflect.FastTrack`
- def currentMirror: universe.Mirror = ??? // macro
+ def currentMirror: universe.Mirror = macro ???
}
package runtime {
private[scala] object Macros {
- def currentMirror(c: scala.reflect.macros.Context): c.Expr[universe.Mirror] = {
+ def currentMirror(c: scala.reflect.macros.blackbox.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 scalaPackage = Select(Ident(newTermName("_root_")), newTermName("scala"))
+ val runtimeUniverse = Select(Select(Select(scalaPackage, newTermName("reflect")), newTermName("runtime")), newTermName("universe"))
val currentMirror = Apply(Select(runtimeUniverse, newTermName("runtimeMirror")), List(Select(runtimeClass, newTermName("getClassLoader"))))
c.Expr[Nothing](currentMirror)(c.WeakTypeTag.Nothing)
}