summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2012-04-12 18:55:13 -0700
committerMartin Odersky <odersky@gmail.com>2012-04-12 18:55:13 -0700
commit6061a22fcd3480e18e60254ad06c8a46b2f1ce53 (patch)
tree12e7d3a1798a186d641e3de21430fc6de0470727 /src/compiler
parentf7a0558059559305a88ffa2c28506b29b2bc57f2 (diff)
parent39a88f5680c3a16bf7ca856683989a2f5481bf69 (diff)
downloadscala-6061a22fcd3480e18e60254ad06c8a46b2f1ce53.tar.gz
scala-6061a22fcd3480e18e60254ad06c8a46b2f1ce53.tar.bz2
scala-6061a22fcd3480e18e60254ad06c8a46b2f1ce53.zip
Merge branch 'master' into topic/sip18
Conflicts: src/compiler/scala/reflect/internal/Definitions.scala Various improvements to SIP 18 reporting. Made scala library and compiler feature-clean.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/reflect/internal/AnnotationInfos.scala17
-rw-r--r--src/compiler/scala/reflect/internal/CapturedVariables.scala36
-rw-r--r--src/compiler/scala/reflect/internal/Constants.scala10
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala260
-rw-r--r--src/compiler/scala/reflect/internal/Flags.scala101
-rw-r--r--src/compiler/scala/reflect/internal/FreeVars.scala60
-rw-r--r--src/compiler/scala/reflect/internal/HasFlags.scala181
-rw-r--r--src/compiler/scala/reflect/internal/Importers.scala51
-rw-r--r--src/compiler/scala/reflect/internal/NameManglers.scala22
-rw-r--r--src/compiler/scala/reflect/internal/Positions.scala38
-rw-r--r--src/compiler/scala/reflect/internal/Reporters.scala74
-rw-r--r--src/compiler/scala/reflect/internal/Required.scala2
-rw-r--r--src/compiler/scala/reflect/internal/StdNames.scala129
-rw-r--r--src/compiler/scala/reflect/internal/SymbolCreations.scala113
-rw-r--r--src/compiler/scala/reflect/internal/SymbolFlags.scala176
-rw-r--r--src/compiler/scala/reflect/internal/SymbolTable.scala20
-rw-r--r--src/compiler/scala/reflect/internal/Symbols.scala1303
-rw-r--r--src/compiler/scala/reflect/internal/TreeBuildUtil.scala62
-rw-r--r--src/compiler/scala/reflect/internal/TreeGen.scala2
-rw-r--r--src/compiler/scala/reflect/internal/TreeInfo.scala194
-rw-r--r--src/compiler/scala/reflect/internal/TreePrinters.scala7
-rw-r--r--src/compiler/scala/reflect/internal/Trees.scala86
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala67
-rw-r--r--src/compiler/scala/reflect/internal/pickling/UnPickler.scala27
-rw-r--r--src/compiler/scala/reflect/internal/transform/Erasure.scala7
-rw-r--r--src/compiler/scala/reflect/internal/transform/UnCurry.scala16
-rw-r--r--src/compiler/scala/reflect/internal/util/Collections.scala5
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Aliases.scala21
-rw-r--r--src/compiler/scala/reflect/makro/runtime/CapturedVariables.scala14
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Context.scala26
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Enclosures.scala36
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Errors.scala6
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Infrastructure.scala34
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Names.scala20
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Reifiers.scala69
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Reporters.scala44
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Settings.scala36
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Symbols.scala8
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Typers.scala78
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Util.scala34
-rw-r--r--src/compiler/scala/reflect/reify/Errors.scala63
-rw-r--r--src/compiler/scala/reflect/reify/NodePrinters.scala111
-rw-r--r--src/compiler/scala/reflect/reify/Phases.scala42
-rw-r--r--src/compiler/scala/reflect/reify/Reifiers.scala154
-rw-r--r--src/compiler/scala/reflect/reify/codegen/Names.scala15
-rw-r--r--src/compiler/scala/reflect/reify/codegen/Positions.scala18
-rw-r--r--src/compiler/scala/reflect/reify/codegen/Symbols.scala111
-rw-r--r--src/compiler/scala/reflect/reify/codegen/Trees.scala220
-rw-r--r--src/compiler/scala/reflect/reify/codegen/Types.scala226
-rw-r--r--src/compiler/scala/reflect/reify/codegen/Util.scala112
-rw-r--r--src/compiler/scala/reflect/reify/package.scala22
-rw-r--r--src/compiler/scala/reflect/reify/phases/Calculate.scala61
-rw-r--r--src/compiler/scala/reflect/reify/phases/Metalevels.scala148
-rw-r--r--src/compiler/scala/reflect/reify/phases/Reify.scala42
-rw-r--r--src/compiler/scala/reflect/reify/phases/Reshape.scala296
-rw-r--r--src/compiler/scala/reflect/runtime/ClassLoaders.scala25
-rw-r--r--src/compiler/scala/reflect/runtime/ConversionUtil.scala1
-rw-r--r--src/compiler/scala/reflect/runtime/JavaToScala.scala209
-rw-r--r--src/compiler/scala/reflect/runtime/Memoizer.scala15
-rw-r--r--src/compiler/scala/reflect/runtime/Mirror.scala36
-rw-r--r--src/compiler/scala/reflect/runtime/RuntimeTypes.scala27
-rw-r--r--src/compiler/scala/reflect/runtime/SymbolLoaders.scala (renamed from src/compiler/scala/reflect/runtime/Loaders.scala)7
-rw-r--r--src/compiler/scala/reflect/runtime/SymbolTable.scala23
-rw-r--r--src/compiler/scala/reflect/runtime/SynchronizedSymbols.scala69
-rw-r--r--src/compiler/scala/reflect/runtime/ToolBoxes.scala363
-rw-r--r--src/compiler/scala/reflect/runtime/TreeBuildUtil.scala49
-rw-r--r--src/compiler/scala/reflect/runtime/Universe.scala20
-rw-r--r--src/compiler/scala/reflect/runtime/package.scala5
-rw-r--r--src/compiler/scala/tools/cmd/FromString.scala4
-rw-r--r--src/compiler/scala/tools/nsc/ClassLoaders.scala64
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala52
-rw-r--r--src/compiler/scala/tools/nsc/MacroContext.scala10
-rw-r--r--src/compiler/scala/tools/nsc/ReflectGlobal.scala7
-rw-r--r--src/compiler/scala/tools/nsc/ReflectMain.scala11
-rw-r--r--src/compiler/scala/tools/nsc/ToolBoxes.scala85
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/DocComments.scala14
-rw-r--r--src/compiler/scala/tools/nsc/ast/FreeVars.scala26
-rw-r--r--src/compiler/scala/tools/nsc/ast/NodePrinters.scala32
-rw-r--r--src/compiler/scala/tools/nsc/ast/Positions.scala44
-rw-r--r--src/compiler/scala/tools/nsc/ast/Reifiers.scala761
-rw-r--r--src/compiler/scala/tools/nsc/ast/ReifyPrinters.scala75
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeDSL.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala16
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeInfo.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala124
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala149
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Scanners.scala3
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Tokens.scala1
-rw-r--r--src/compiler/scala/tools/nsc/backend/JavaPlatform.scala8
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala16
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala6
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Global.scala3
-rw-r--r--src/compiler/scala/tools/nsc/interactive/RangePositions.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ILoop.scala8
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IMain.scala106
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Naming.scala4
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Power.scala1
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ReplVals.scala7
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/RichClass.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala9
-rw-r--r--src/compiler/scala/tools/nsc/matching/Patterns.scala6
-rw-r--r--src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala11
-rw-r--r--src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala1
-rw-r--r--src/compiler/scala/tools/nsc/scratchpad/Executor.scala2
-rw-r--r--src/compiler/scala/tools/nsc/settings/MutableSettings.scala2
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala149
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Positions.scala30
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala3
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/AddInterfaces.scala133
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala12
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala8
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Flatten.scala5
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala24
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala22
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala63
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala24
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala43
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala33
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala190
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala26
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala1361
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala158
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala81
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala7
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala28
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala19
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala23
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala276
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Unapplies.scala15
-rw-r--r--src/compiler/scala/tools/nsc/util/ClassPath.scala2
-rw-r--r--src/compiler/scala/tools/nsc/util/Position.scala126
-rw-r--r--src/compiler/scala/tools/reflect/package.scala2
142 files changed, 7274 insertions, 3273 deletions
diff --git a/src/compiler/scala/reflect/internal/AnnotationInfos.scala b/src/compiler/scala/reflect/internal/AnnotationInfos.scala
index 9a7c79d856..b86c62661a 100644
--- a/src/compiler/scala/reflect/internal/AnnotationInfos.scala
+++ b/src/compiler/scala/reflect/internal/AnnotationInfos.scala
@@ -116,7 +116,7 @@ trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable =>
// Classfile annot: args empty. Scala annot: assocs empty.
assert(args.isEmpty || assocs.isEmpty, atp)
- // @xeno.by: necessary for reification, see Reifiers.scala for more info
+ // necessary for reification, see Reifiers.scala for more info
private var orig: Tree = EmptyTree
def original = orig
def setOriginal(t: Tree): this.type = { orig = t; this }
@@ -168,24 +168,15 @@ trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable =>
*
* `assocs` stores arguments to classfile annotations as name-value pairs.
*/
- sealed abstract class AnnotationInfo extends Product3[Type, List[Tree], List[(Name, ClassfileAnnotArg)]] {
+ sealed abstract class AnnotationInfo {
def atp: Type
def args: List[Tree]
def assocs: List[(Name, ClassfileAnnotArg)]
- // @xeno.by: necessary for reification, see Reifiers.scala for more info
+ // necessary for reification, see Reifiers.scala for more info
def original: Tree
def setOriginal(t: Tree): this.type
- /** Hand rolling Product. */
- def _1 = atp
- def _2 = args
- def _3 = assocs
- // @xeno.by: original hasn't become a product member for backward compatibility purposes
- // def _4 = original
- def canEqual(other: Any) = other.isInstanceOf[AnnotationInfo]
- override def productPrefix = "AnnotationInfo"
-
// see annotationArgRewriter
lazy val isTrivial = atp.isTrivial && !hasArgWhich(_.isInstanceOf[This])
@@ -270,7 +261,7 @@ trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable =>
}
lazy val classfileAnnotArgManifest: ClassManifest[ClassfileAnnotArg] =
- reflect.ClassManifest.classType(classOf[ClassfileAnnotArg])
+ reflect.ClassManifest[ClassfileAnnotArg](classOf[ClassfileAnnotArg])
object UnmappableAnnotation extends CompleteAnnotationInfo(NoType, Nil, Nil)
}
diff --git a/src/compiler/scala/reflect/internal/CapturedVariables.scala b/src/compiler/scala/reflect/internal/CapturedVariables.scala
new file mode 100644
index 0000000000..77909d9157
--- /dev/null
+++ b/src/compiler/scala/reflect/internal/CapturedVariables.scala
@@ -0,0 +1,36 @@
+package scala.reflect
+package internal
+
+import Flags._
+
+trait CapturedVariables { self: SymbolTable =>
+
+ import definitions._
+
+ /** Mark a variable as captured; i.e. force boxing in a *Ref type.
+ */
+ def captureVariable(vble: Symbol): Unit = vble setFlag CAPTURED
+
+ /** Mark given identifier as a reference to a captured variable itself
+ * suppressing dereferencing with the `elem` field.
+ */
+ def referenceCapturedVariable(vble: Symbol): Tree = ReferenceToBoxed(Ident(vble))
+
+ /** Convert type of a captured variable to *Ref type.
+ */
+ def capturedVariableType(vble: Symbol): Type =
+ capturedVariableType(vble, NoType, false)
+
+ /** Convert type of a captured variable to *Ref type.
+ */
+ def capturedVariableType(vble: Symbol, tpe: Type = NoType, erasedTypes: Boolean = false): Type = {
+ val tpe1 = if (tpe == NoType) vble.tpe else tpe
+ val symClass = tpe1.typeSymbol
+ def refType(valueRef: Map[Symbol, Symbol], objectRefClass: Symbol) =
+ if (isPrimitiveValueClass(symClass) && symClass != UnitClass) valueRef(symClass).tpe
+ else if (erasedTypes) objectRefClass.tpe
+ else appliedType(objectRefClass, tpe)
+ if (vble.hasAnnotation(VolatileAttr)) refType(volatileRefClass, VolatileObjectRefClass)
+ else refType(refClass, ObjectRefClass)
+ }
+}
diff --git a/src/compiler/scala/reflect/internal/Constants.scala b/src/compiler/scala/reflect/internal/Constants.scala
index c328cc49cb..135d18d5ad 100644
--- a/src/compiler/scala/reflect/internal/Constants.scala
+++ b/src/compiler/scala/reflect/internal/Constants.scala
@@ -26,7 +26,7 @@ trait Constants extends api.Constants {
final val DoubleTag = 9
final val StringTag = 10
final val NullTag = 11
- final val ClassTag = 12
+ final val ClazzTag = 12
// For supporting java enumerations inside java annotations (see ClassfileParser)
final val EnumTag = 13
@@ -43,7 +43,7 @@ trait Constants extends api.Constants {
case x: Double => DoubleTag
case x: String => StringTag
case x: Char => CharTag
- case x: Type => ClassTag
+ case x: Type => ClazzTag
case x: Symbol => EnumTag
case _ => throw new Error("bad constant value: " + value + " of class " + value.getClass)
}
@@ -70,7 +70,7 @@ trait Constants extends api.Constants {
case DoubleTag => DoubleClass.tpe
case StringTag => StringClass.tpe
case NullTag => NullClass.tpe
- case ClassTag => ClassType(value.asInstanceOf[Type])
+ case ClazzTag => ClassType(value.asInstanceOf[Type])
case EnumTag =>
// given (in java): "class A { enum E { VAL1 } }"
// - symbolValue: the symbol of the actual enumeration value (VAL1)
@@ -201,7 +201,7 @@ trait Constants extends api.Constants {
def stringValue: String =
if (value == null) "null"
- else if (tag == ClassTag) signature(typeValue)
+ else if (tag == ClazzTag) signature(typeValue)
else value.toString()
@switch def escapedChar(ch: Char): String = ch match {
@@ -221,7 +221,7 @@ trait Constants extends api.Constants {
tag match {
case NullTag => "null"
case StringTag => "\"" + escape(stringValue) + "\""
- case ClassTag => "classOf[" + signature(typeValue) + "]"
+ case ClazzTag => "classOf[" + signature(typeValue) + "]"
case CharTag => "'" + escapedChar(charValue) + "'"
case LongTag => longValue.toString() + "L"
case _ => String.valueOf(value)
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala
index d3a9821596..6689a9dbb8 100644
--- a/src/compiler/scala/reflect/internal/Definitions.scala
+++ b/src/compiler/scala/reflect/internal/Definitions.scala
@@ -10,10 +10,29 @@ import annotation.{ switch }
import scala.collection.{ mutable, immutable }
import Flags._
import PartialFunction._
+import scala.reflect.{ mirror => rm }
trait Definitions extends reflect.api.StandardDefinitions {
self: SymbolTable =>
+ // [Eugene] find a way to make these non-lazy
+ lazy val ByteTpe = definitions.ByteClass.asType
+ lazy val ShortTpe = definitions.ShortClass.asType
+ lazy val CharTpe = definitions.CharClass.asType
+ lazy val IntTpe = definitions.IntClass.asType
+ lazy val LongTpe = definitions.LongClass.asType
+ lazy val FloatTpe = definitions.FloatClass.asType
+ lazy val DoubleTpe = definitions.DoubleClass.asType
+ lazy val BooleanTpe = definitions.BooleanClass.asType
+ lazy val UnitTpe = definitions.UnitClass.asType
+ lazy val AnyTpe = definitions.AnyClass.asType
+ lazy val ObjectTpe = definitions.ObjectClass.asType
+ lazy val AnyValTpe = definitions.AnyValClass.asType
+ lazy val AnyRefTpe = definitions.AnyRefClass.asType
+ lazy val NothingTpe = definitions.NothingClass.asType
+ lazy val NullTpe = definitions.NullClass.asType
+ lazy val StringTpe = definitions.StringClass.asType
+
/** Since both the value parameter types and the result type may
* require access to the type parameter symbols, we model polymorphic
* creation as a function from those symbols to (formal types, result type).
@@ -129,6 +148,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
DoubleClass
)
def ScalaValueClassCompanions: List[Symbol] = ScalaValueClasses map (_.companionSymbol)
+ def ScalaPrimitiveValueClasses: List[Symbol] = ScalaValueClasses
}
object definitions extends AbsDefinitions with ValueClassDefinitions {
@@ -138,6 +158,12 @@ trait Definitions extends reflect.api.StandardDefinitions {
// symbols related to packages
var emptypackagescope: Scope = null //debug
+ // TODO - having these as objects means they elude the attempt to
+ // add synchronization in SynchronizedSymbols. But we should either
+ // flip on object overrides or find some other accomodation, because
+ // lazy vals are unnecessarily expensive relative to objects and it
+ // is very beneficial for a handful of bootstrap symbols to have
+ // first class identities
sealed trait WellKnownSymbol extends Symbol {
this initFlags TopLevelCreationFlags
}
@@ -145,10 +171,12 @@ trait Definitions extends reflect.api.StandardDefinitions {
// type and term symbols respectively.
sealed trait RootSymbol extends WellKnownSymbol {
final override def isRootSymbol = true
+ override def owner = NoSymbol
+ override def typeOfThis = thisSym.tpe
}
// This is the package _root_. The actual root cannot be referenced at
// the source level, but _root_ is essentially a function => <root>.
- final object RootPackage extends ModuleSymbol(NoSymbol, NoPosition, nme.ROOTPKG) with RootSymbol {
+ final object RootPackage extends PackageSymbol(NoSymbol, NoPosition, nme.ROOTPKG) with RootSymbol {
this setInfo NullaryMethodType(RootClass.tpe)
RootClass.sourceModule = this
@@ -160,7 +188,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
// 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 ModuleClassSymbol(NoSymbol, NoPosition, tpnme.ROOT) with RootSymbol {
+ final object RootClass extends PackageClassSymbol(NoSymbol, NoPosition, tpnme.ROOT) with RootSymbol {
this setInfo rootLoader
override def isRoot = true
@@ -170,10 +198,10 @@ trait Definitions extends reflect.api.StandardDefinitions {
override def ownerOfNewSymbols = EmptyPackageClass
}
// The empty package, which holds all top level types without given packages.
- final object EmptyPackage extends ModuleSymbol(RootClass, NoPosition, nme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
+ final object EmptyPackage extends PackageSymbol(RootClass, NoPosition, nme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
override def isEmptyPackage = true
}
- final object EmptyPackageClass extends ModuleClassSymbol(RootClass, NoPosition, tpnme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
+ final object EmptyPackageClass extends PackageClassSymbol(RootClass, NoPosition, tpnme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
override def isEffectiveRoot = true
override def isEmptyPackageClass = true
}
@@ -190,14 +218,14 @@ trait Definitions extends reflect.api.StandardDefinitions {
lazy val JavaLangEnumClass = getRequiredClass("java.lang.Enum")
// convenient one-argument parameter lists
- lazy val anyparam = List(AnyClass.typeConstructor)
+ 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.typeConstructor
- private def inttype = IntClass.typeConstructor
- private def stringtype = StringClass.typeConstructor
+ private def booltype = BooleanClass.tpe
+ private def inttype = IntClass.tpe
+ private def stringtype = StringClass.tpe
// Java types
def javaTypeName(jclazz: Class[_]): TypeName = newTypeName(jclazz.getName)
@@ -241,7 +269,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
// top types
lazy val AnyClass = enterNewClass(ScalaPackageClass, tpnme.Any, Nil, ABSTRACT)
- lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectClass.typeConstructor)
+ lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectClass.tpe)
lazy val ObjectClass = getClass(sn.Object)
// Note: this is not the type alias AnyRef, it's a companion-like
@@ -368,10 +396,10 @@ trait Definitions extends reflect.api.StandardDefinitions {
lazy val RemoteInterfaceClass = getRequiredClass("java.rmi.Remote")
lazy val RemoteExceptionClass = getRequiredClass("java.rmi.RemoteException")
- lazy val ByNameParamClass = specialPolyClass(tpnme.BYNAME_PARAM_CLASS_NAME, COVARIANT)(_ => AnyClass.typeConstructor)
- lazy val EqualsPatternClass = specialPolyClass(tpnme.EQUALS_PATTERN_NAME, 0L)(_ => AnyClass.typeConstructor)
- lazy val JavaRepeatedParamClass = specialPolyClass(tpnme.JAVA_REPEATED_PARAM_CLASS_NAME, COVARIANT)(tparam => arrayType(tparam.typeConstructor))
- lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS_NAME, COVARIANT)(tparam => seqType(tparam.typeConstructor))
+ lazy val ByNameParamClass = specialPolyClass(tpnme.BYNAME_PARAM_CLASS_NAME, COVARIANT)(_ => AnyClass.tpe)
+ lazy val EqualsPatternClass = specialPolyClass(tpnme.EQUALS_PATTERN_NAME, 0L)(_ => AnyClass.tpe)
+ lazy val JavaRepeatedParamClass = specialPolyClass(tpnme.JAVA_REPEATED_PARAM_CLASS_NAME, COVARIANT)(tparam => arrayType(tparam.tpe))
+ lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS_NAME, COVARIANT)(tparam => seqType(tparam.tpe))
def isByNameParamType(tp: Type) = tp.typeSymbol == ByNameParamClass
def isScalaRepeatedParamType(tp: Type) = tp.typeSymbol == RepeatedParamClass
@@ -380,10 +408,10 @@ trait Definitions extends reflect.api.StandardDefinitions {
def isCastSymbol(sym: Symbol) = sym == Any_asInstanceOf || sym == Object_asInstanceOf
def isJavaVarArgsMethod(m: Symbol) = m.isMethod && isJavaVarArgs(m.info.params)
- def isJavaVarArgs(params: List[Symbol]) = params.nonEmpty && isJavaRepeatedParamType(params.last.tpe)
- def isScalaVarArgs(params: List[Symbol]) = params.nonEmpty && isScalaRepeatedParamType(params.last.tpe)
- def isVarArgsList(params: List[Symbol]) = params.nonEmpty && isRepeatedParamType(params.last.tpe)
- def isVarArgTypes(formals: List[Type]) = formals.nonEmpty && isRepeatedParamType(formals.last)
+ def isJavaVarArgs(params: Seq[Symbol]) = params.nonEmpty && isJavaRepeatedParamType(params.last.tpe)
+ def isScalaVarArgs(params: Seq[Symbol]) = params.nonEmpty && isScalaRepeatedParamType(params.last.tpe)
+ def isVarArgsList(params: Seq[Symbol]) = params.nonEmpty && isRepeatedParamType(params.last.tpe)
+ def isVarArgTypes(formals: Seq[Type]) = formals.nonEmpty && isRepeatedParamType(formals.last)
def hasRepeatedParam(tp: Type): Boolean = tp match {
case MethodType(formals, restpe) => isScalaVarArgs(formals) || hasRepeatedParam(restpe)
@@ -438,19 +466,38 @@ trait Definitions extends reflect.api.StandardDefinitions {
def methodCache_add = getMember(MethodCacheClass, nme.add_)
// scala.reflect
- lazy val ReflectApiUniverse = getRequiredClass("scala.reflect.api.Universe")
- lazy val ReflectMacroContext = getRequiredClass("scala.reflect.macro.Context")
- lazy val ReflectRuntimeMirror = getRequiredModule("scala.reflect.runtime.Mirror")
- def freeValueMethod = getMember(ReflectRuntimeMirror, nme.freeValue)
+ lazy val ReflectPackageClass = getMember(ScalaPackageClass, nme.reflect)
lazy val ReflectPackage = getPackageObject("scala.reflect")
def Reflect_mirror = getMember(ReflectPackage, nme.mirror)
- lazy val PartialManifestClass = getRequiredClass("scala.reflect.ClassManifest")
- lazy val PartialManifestModule = getRequiredModule("scala.reflect.ClassManifest")
- lazy val FullManifestClass = getRequiredClass("scala.reflect.Manifest")
- lazy val FullManifestModule = getRequiredModule("scala.reflect.Manifest")
- lazy val OptManifestClass = getRequiredClass("scala.reflect.OptManifest")
- lazy val NoManifest = getRequiredModule("scala.reflect.NoManifest")
+ lazy val ExprClass = getMember(getRequiredClass("scala.reflect.api.Exprs"), tpnme.Expr)
+ def ExprTree = getMember(ExprClass, nme.tree)
+ def ExprTpe = getMember(ExprClass, nme.tpe)
+ def ExprEval = getMember(ExprClass, nme.eval)
+ def ExprValue = getMember(ExprClass, nme.value)
+ lazy val ExprModule = getMember(getRequiredClass("scala.reflect.api.Exprs"), nme.Expr)
+
+ lazy val ClassTagClass = getRequiredClass("scala.reflect.ClassTag")
+ def ClassTagErasure = getMember(ClassTagClass, nme.erasure)
+ def ClassTagTpe = getMember(ClassTagClass, nme.tpe)
+ lazy val ClassTagModule = getRequiredModule("scala.reflect.ClassTag")
+ lazy val TypeTagsClass = getRequiredClass("scala.reflect.api.TypeTags")
+ lazy val TypeTagClass = getMember(TypeTagsClass, tpnme.TypeTag)
+ def TypeTagTpe = getMember(TypeTagClass, nme.tpe)
+ lazy val TypeTagModule = getMember(TypeTagsClass, nme.TypeTag)
+ lazy val ConcreteTypeTagClass = getMember(TypeTagsClass, tpnme.ConcreteTypeTag)
+ lazy val ConcreteTypeTagModule = getMember(TypeTagsClass, nme.ConcreteTypeTag)
+
+ lazy val MacroContextClass = getRequiredClass("scala.reflect.makro.Context")
+ def MacroContextPrefix = getMember(MacroContextClass, nme.prefix)
+ def MacroContextPrefixType = getMember(MacroContextClass, tpnme.PrefixType)
+ def MacroContextMirror = getMember(MacroContextClass, nme.mirror)
+ def MacroContextReify = getMember(MacroContextClass, nme.reify)
+ lazy val MacroImplAnnotation = getRequiredClass("scala.reflect.makro.internal.macroImpl")
+ lazy val MacroInternalPackage = getPackageObject("scala.reflect.makro.internal")
+ def MacroInternal_materializeClassTag = getMember(MacroInternalPackage, nme.materializeClassTag)
+ def MacroInternal_materializeTypeTag = getMember(MacroInternalPackage, nme.materializeTypeTag)
+ def MacroInternal_materializeConcreteTypeTag = getMember(MacroInternalPackage, nme.materializeConcreteTypeTag)
lazy val ScalaSignatureAnnotation = getRequiredClass("scala.reflect.ScalaSignature")
lazy val ScalaLongSignatureAnnotation = getRequiredClass("scala.reflect.ScalaLongSignature")
@@ -461,32 +508,13 @@ trait Definitions extends reflect.api.StandardDefinitions {
lazy val NoneModule: Symbol = getRequiredModule("scala.None")
lazy val SomeModule: Symbol = getRequiredModule("scala.Some")
- /** Note: don't use this manifest/type function for anything important,
- * as it is incomplete. Would love to have things like existential types
- * working, but very unfortunately the manifests just stuff the relevant
- * information into the toString method.
- */
- def manifestToType(m: OptManifest[_]): Type = m match {
- case m: ClassManifest[_] =>
- val sym = manifestToSymbol(m)
- val args = m.typeArguments
+ // [Eugene] how do I make this work without casts?
+ // private lazy val importerFromRm = self.mkImporter(rm)
+ private lazy val importerFromRm = self.mkImporter(rm).asInstanceOf[self.Importer { val from: rm.type }]
- if ((sym eq NoSymbol) || args.isEmpty) sym.tpe
- else appliedType(sym.typeConstructor, args map manifestToType)
- case _ =>
- NoType
- }
+ def manifestToType(m: Manifest[_]): Type = importerFromRm.importType(m.tpe)
- def manifestToSymbol(m: ClassManifest[_]): Symbol = m match {
- case x: scala.reflect.AnyValManifest[_] =>
- getMember(ScalaPackageClass, newTypeName("" + x))
- case _ =>
- val name = m.erasure.getName
- if (name endsWith nme.MODULE_SUFFIX_STRING)
- getModuleIfDefined(name stripSuffix nme.MODULE_SUFFIX_STRING)
- else
- getClassIfDefined(name)
- }
+ def manifestToSymbol(m: Manifest[_]): Symbol = importerFromRm.importSymbol(m.tpe.typeSymbol)
// The given symbol represents either String.+ or StringAdd.+
def isStringAddition(sym: Symbol) = sym == String_+ || sym == StringAdd_+
@@ -503,33 +531,34 @@ trait Definitions extends reflect.api.StandardDefinitions {
def hasJavaMainMethod(path: String): Boolean =
hasJavaMainMethod(getModuleIfDefined(path))
- def isOptionType(tp: Type) = cond(tp.normalize) { case TypeRef(_, OptionClass, List(_)) => true }
- def isSomeType(tp: Type) = cond(tp.normalize) { case TypeRef(_, SomeClass, List(_)) => true }
- def isNoneType(tp: Type) = cond(tp.normalize) { case TypeRef(_, NoneModule, List(_)) => true }
-
- def optionType(tp: Type) = typeRef(NoPrefix, OptionClass, List(tp))
- def someType(tp: Type) = typeRef(NoPrefix, SomeClass, List(tp))
- def symbolType = typeRef(SymbolClass.typeConstructor.prefix, SymbolClass, List())
- def longType = typeRef(LongClass.typeConstructor.prefix, LongClass, List())
+ 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
+ // Product, Tuple, Function, AbstractFunction
private def mkArityArray(name: String, arity: Int, countFrom: Int = 1): Array[Symbol] = {
val list = countFrom to arity map (i => getRequiredClass("scala." + name + i))
if (countFrom == 0) list.toArray
else (NoSymbol +: list).toArray
}
+ private def aritySpecificType(symbolArray: Array[Symbol], args: List[Type], others: Type*): Type = {
+ val arity = args.length
+ if (arity >= symbolArray.length) NoType
+ else appliedType(symbolArray(arity), args ++ others: _*)
+ }
val MaxTupleArity, MaxProductArity, MaxFunctionArity = 22
- /** The maximal dimensions of a generic array creation.
- * I.e. new Array[Array[Array[Array[Array[T]]]]] creates a 5 times
- * nested array. More is not allowed.
- */
- val MaxArrayDims = 5
- lazy val TupleClass = mkArityArray("Tuple", MaxTupleArity)
- lazy val ProductClass = mkArityArray("Product", MaxProductArity)
- lazy val FunctionClass = mkArityArray("Function", MaxFunctionArity, 0)
+ lazy val ProductClass = { val arr = mkArityArray("Product", MaxProductArity) ; arr(0) = UnitClass ; arr }
+ lazy val TupleClass = mkArityArray("Tuple", MaxTupleArity)
+ lazy val FunctionClass = mkArityArray("Function", MaxFunctionArity, 0)
lazy val AbstractFunctionClass = mkArityArray("runtime.AbstractFunction", MaxFunctionArity, 0)
- lazy val isProductNClass = ProductClass.toSet
+
+ /** Creators for TupleN, ProductN, FunctionN. */
+ def tupleType(elems: List[Type]) = aritySpecificType(TupleClass, elems)
+ def productType(elems: List[Type]) = aritySpecificType(ProductClass, elems)
+ def functionType(formals: List[Type], restpe: Type) = aritySpecificType(FunctionClass, formals, restpe)
+ def abstractFunctionType(formals: List[Type], restpe: Type) = aritySpecificType(AbstractFunctionClass, formals, restpe)
+
def wrapArrayMethodName(elemtp: Type): TermName = elemtp.typeSymbol match {
case ByteClass => nme.wrapByteArray
case ShortClass => nme.wrapShortArray
@@ -546,10 +575,11 @@ trait Definitions extends reflect.api.StandardDefinitions {
}
@deprecated("Use isTupleType", "2.10.0")
- def isTupleTypeOrSubtype(tp: Type): Boolean = isTupleType(tp)
+ def isTupleTypeOrSubtype(tp: Type) = isTupleType(tp)
def tupleField(n: Int, j: Int) = getMember(TupleClass(n), nme.productAccessorName(j))
def isTupleSymbol(sym: Symbol) = TupleClass contains unspecializedSymbol(sym)
+ def isProductNClass(sym: Symbol) = ProductClass contains sym
def unspecializedSymbol(sym: Symbol): Symbol = {
if (sym hasFlag SPECIALIZED) {
@@ -586,14 +616,6 @@ trait Definitions extends reflect.api.StandardDefinitions {
}
def isTupleType(tp: Type) = isTupleTypeDirect(tp.normalize)
- def tupleType(elems: List[Type]) = {
- val len = elems.length
- if (len <= MaxTupleArity) {
- val sym = TupleClass(len)
- typeRef(sym.typeConstructor.prefix, sym, elems)
- } else NoType
- }
-
lazy val ProductRootClass: Symbol = getRequiredClass("scala.Product")
def Product_productArity = getMember(ProductRootClass, nme.productArity)
def Product_productElement = getMember(ProductRootClass, nme.productElement)
@@ -608,18 +630,6 @@ trait Definitions extends reflect.api.StandardDefinitions {
/** returns true if this type is exactly ProductN[T1,...,Tn], not some subclass */
def isExactProductType(tp: Type): Boolean = isProductNClass(tp.typeSymbol)
- def productType(elems: List[Type]) = {
- if (elems.isEmpty) UnitClass.tpe
- else {
- val len = elems.length
- if (len <= MaxProductArity) {
- val sym = ProductClass(len)
- typeRef(sym.typeConstructor.prefix, sym, elems)
- }
- else NoType
- }
- }
-
/** if tpe <: ProductN[T1,...,TN], returns List(T1,...,TN) else Nil */
def getProductArgs(tpe: Type): List[Type] = tpe.baseClasses find isProductNClass match {
case Some(x) => tpe.baseType(x).typeArgs
@@ -632,21 +642,10 @@ trait Definitions extends reflect.api.StandardDefinitions {
}
def functionApply(n: Int) = getMember(FunctionClass(n), nme.apply)
- def functionType(formals: List[Type], restpe: Type) = {
- val len = formals.length
- if (len <= MaxFunctionArity) {
- val sym = FunctionClass(len)
- typeRef(sym.typeConstructor.prefix, sym, formals :+ restpe)
- } else NoType
- }
- def abstractFunctionForFunctionType(tp: Type) = tp.normalize match {
- case tr @ TypeRef(_, _, args) if isFunctionType(tr) =>
- val sym = AbstractFunctionClass(args.length - 1)
- typeRef(sym.typeConstructor.prefix, sym, args)
- case _ =>
- NoType
- }
+ def abstractFunctionForFunctionType(tp: Type) =
+ if (isFunctionType(tp)) abstractFunctionType(tp.typeArgs.init, tp.typeArgs.last)
+ else NoType
def isFunctionType(tp: Type): Boolean = tp.normalize match {
case TypeRef(_, sym, args) if args.nonEmpty =>
@@ -663,17 +662,21 @@ trait Definitions extends reflect.api.StandardDefinitions {
case _ => NoType
}
- def seqType(arg: Type) = appliedType(SeqClass.typeConstructor, List(arg))
- def arrayType(arg: Type) = appliedType(ArrayClass.typeConstructor, List(arg))
- def byNameType(arg: Type) = appliedType(ByNameParamClass.typeConstructor, List(arg))
- def iteratorOfType(tp: Type) = appliedType(IteratorClass.typeConstructor, List(tp))
+ def arrayType(arg: Type) = appliedType(ArrayClass, arg)
+ def byNameType(arg: Type) = appliedType(ByNameParamClass, arg)
+ def iteratorOfType(tp: Type) = appliedType(IteratorClass, tp)
+ def javaRepeatedType(arg: Type) = appliedType(JavaRepeatedParamClass, arg)
+ def optionType(tp: Type) = appliedType(OptionClass, tp)
+ def scalaRepeatedType(arg: Type) = appliedType(RepeatedParamClass, arg)
+ def seqType(arg: Type) = appliedType(SeqClass, arg)
+ def someType(tp: Type) = appliedType(SomeClass, tp)
- lazy val StringArray = arrayType(StringClass.tpe)
+ def StringArray = arrayType(StringClass.tpe)
lazy val ObjectArray = arrayType(ObjectClass.tpe)
def ClassType(arg: Type) =
if (phase.erasedTypes || forMSIL) ClassClass.tpe
- else appliedType(ClassClass.typeConstructor, List(arg))
+ else appliedType(ClassClass, arg)
def vmClassType(arg: Type): Type = ClassType(arg)
def vmSignature(sym: Symbol, info: Type): String = signature(info) // !!!
@@ -857,7 +860,8 @@ trait Definitions extends reflect.api.StandardDefinitions {
// boxed classes
lazy val ObjectRefClass = getRequiredClass("scala.runtime.ObjectRef")
lazy val VolatileObjectRefClass = getRequiredClass("scala.runtime.VolatileObjectRef")
- lazy val BoxesRunTimeClass = getRequiredModule("scala.runtime.BoxesRunTime")
+ lazy val BoxesRunTimeModule = getRequiredModule("scala.runtime.BoxesRunTime")
+ lazy val BoxesRunTimeClass = BoxesRunTimeModule.moduleClass
lazy val BoxedNumberClass = getClass(sn.BoxedNumber)
lazy val BoxedCharacterClass = getClass(sn.BoxedCharacter)
lazy val BoxedBooleanClass = getClass(sn.BoxedBoolean)
@@ -868,6 +872,9 @@ trait Definitions extends reflect.api.StandardDefinitions {
lazy val BoxedFloatClass = getRequiredClass("java.lang.Float")
lazy val BoxedDoubleClass = getRequiredClass("java.lang.Double")
+ lazy val Boxes_isNumberOrBool = getDecl(BoxesRunTimeClass, nme.isBoxedNumberOrBoolean)
+ lazy val Boxes_isNumber = getDecl(BoxesRunTimeClass, nme.isBoxedNumber)
+
lazy val BoxedUnitClass = getRequiredClass("scala.runtime.BoxedUnit")
lazy val BoxedUnitModule = getRequiredModule("scala.runtime.BoxedUnit")
def BoxedUnit_UNIT = getMember(BoxedUnitModule, nme.UNIT)
@@ -914,6 +921,9 @@ trait Definitions extends reflect.api.StandardDefinitions {
lazy val GetterTargetClass = getMetaAnnotation("getter")
lazy val ParamTargetClass = getMetaAnnotation("param")
lazy val SetterTargetClass = getMetaAnnotation("setter")
+ lazy val ClassTargetClass = getMetaAnnotation("companionClass")
+ lazy val ObjectTargetClass = getMetaAnnotation("companionObject")
+ lazy val MethodTargetClass = getMetaAnnotation("companionMethod") // TODO: module, moduleClass? package, packageObject?
lazy val LanguageFeatureClass = getMetaAnnotation("languageFeature")
// Language features
@@ -926,8 +936,6 @@ trait Definitions extends reflect.api.StandardDefinitions {
lazy val HigherKindsFeature = getRequiredClass("scala.languageFeature.higherKinds")
lazy val ExistentialsFeature = getRequiredClass("scala.languageFeature.existentials")
- // TODO: module, moduleClass? package, packageObject?
-
private def getMetaAnnotation(name: String) = getRequiredClass("scala.annotation.meta." + name)
def isMetaAnnotation(sym: Symbol): Boolean = metaAnnotations(sym) || (
// Trying to allow for deprecated locations
@@ -940,7 +948,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
)
lazy val AnnotationDefaultAttr: Symbol = {
- val attr = enterNewClass(RuntimePackageClass, tpnme.AnnotationDefaultATTR, List(AnnotationClass.typeConstructor))
+ 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
@@ -996,13 +1004,25 @@ trait Definitions extends reflect.api.StandardDefinitions {
else findNamedMember(segs.tail, root.info member segs.head)
def getMember(owner: Symbol, name: Name): Symbol = {
- if (owner == NoSymbol) NoSymbol
- else owner.info.nonPrivateMember(name) match {
- case NoSymbol => throw new FatalError(owner + " does not have a member " + name)
- case result => result
+ getMemberIfDefined(owner, name) orElse {
+ throw new FatalError(owner + " does not have a member " + name)
}
}
+ def getMemberIfDefined(owner: Symbol, name: Name): Symbol =
+ owner.info.nonPrivateMember(name)
+ /** Using getDecl rather than getMember may avoid issues with
+ * OverloadedTypes turning up when you don't want them, if you
+ * know the method in question is uniquely declared in the given owner.
+ */
+ def getDecl(owner: Symbol, name: Name): Symbol = {
+ getDeclIfDefined(owner, name) orElse {
+ throw new FatalError(owner + " does not have a decl " + name)
+ }
+ }
+ def getDeclIfDefined(owner: Symbol, name: Name): Symbol =
+ owner.info.nonPrivateDecl(name)
+
def packageExists(packageName: String): Boolean =
getModuleIfDefined(packageName).isPackage
@@ -1073,10 +1093,10 @@ trait Definitions extends reflect.api.StandardDefinitions {
private lazy val boxedValueClassesSet = boxedClass.values.toSet + BoxedUnitClass
/** Is symbol a value class? */
- def isPrimitiveValueClass(sym: Symbol) = scalaValueClassesSet(sym)
+ def isPrimitiveValueClass(sym: Symbol) = ScalaValueClasses contains sym
def isNonUnitValueClass(sym: Symbol) = isPrimitiveValueClass(sym) && (sym != UnitClass)
def isSpecializableClass(sym: Symbol) = isPrimitiveValueClass(sym) || (sym == AnyRefClass)
- def isScalaValueType(tp: Type) = scalaValueClassesSet(tp.typeSymbol)
+ def isScalaValueType(tp: Type) = ScalaValueClasses contains tp.typeSymbol
/** Is symbol a boxed value class, e.g. java.lang.Integer? */
def isBoxedValueClass(sym: Symbol) = boxedValueClassesSet(sym)
diff --git a/src/compiler/scala/reflect/internal/Flags.scala b/src/compiler/scala/reflect/internal/Flags.scala
index ce1c8d0908..ce459bdd06 100644
--- a/src/compiler/scala/reflect/internal/Flags.scala
+++ b/src/compiler/scala/reflect/internal/Flags.scala
@@ -121,9 +121,9 @@ class ModifierFlags {
// Overridden.
def flagToString(flag: Long): String = ""
- final val PrivateLocal: Long = PRIVATE | LOCAL
- final val ProtectedLocal: Long = PROTECTED | LOCAL
- final val AccessFlags: Long = PRIVATE | PROTECTED | LOCAL
+ final val PrivateLocal = PRIVATE | LOCAL
+ final val ProtectedLocal = PROTECTED | LOCAL
+ final val AccessFlags = PRIVATE | PROTECTED | LOCAL
}
object ModifierFlags extends ModifierFlags
@@ -174,6 +174,9 @@ class Flags extends ModifierFlags {
final val LateShift = 47L
final val AntiShift = 56L
+ // Flags which sketchily share the same slot
+ val OverloadedFlagsMask = 0L | BYNAMEPARAM | CONTRAVARIANT | DEFAULTPARAM | EXISTENTIAL | IMPLCLASS
+
// ------- late flags (set by a transformer phase) ---------------------------------
//
// Summary of when these are claimed to be first used.
@@ -206,34 +209,46 @@ class Flags extends ModifierFlags {
// ------- masks -----------------------------------------------------------------------
+ /** To be a little clearer to people who aren't habitual bit twiddlers.
+ */
+ final val AllFlags = -1L
+
/** These flags can be set when class or module symbol is first created.
* They are the only flags to survive a call to resetFlags().
*/
- final val TopLevelCreationFlags: Long =
+ final val TopLevelCreationFlags =
MODULE | PACKAGE | FINAL | JAVA
+ // TODO - there's no call to slap four flags onto every package.
+ final val PackageFlags = TopLevelCreationFlags
+
+ // FINAL not included here due to possibility of object overriding.
+ // In fact, FINAL should not be attached regardless. We should be able
+ // to reconstruct whether an object was marked final in source.
+ final val ModuleFlags = MODULE
+
/** These modifiers can be set explicitly in source programs. This is
* used only as the basis for the default flag mask (which ones to display
* when printing a normal message.)
*/
- final val ExplicitFlags: Long =
+ final val ExplicitFlags =
PRIVATE | PROTECTED | ABSTRACT | FINAL | SEALED |
OVERRIDE | CASE | IMPLICIT | ABSOVERRIDE | LAZY
- /** These modifiers appear in TreePrinter output. */
- final val PrintableFlags: Long =
- ExplicitFlags | LOCAL | SYNTHETIC | STABLE | CASEACCESSOR | MACRO |
- ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | BRIDGE | STATIC | VBRIDGE | SPECIALIZED | SYNCHRONIZED
-
/** The two bridge flags */
final val BridgeFlags = BRIDGE | VBRIDGE
final val BridgeAndPrivateFlags = BridgeFlags | PRIVATE
+ /** These modifiers appear in TreePrinter output. */
+ final val PrintableFlags =
+ ExplicitFlags | BridgeFlags | LOCAL | SYNTHETIC | STABLE | CASEACCESSOR | MACRO |
+ ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | STATIC | SPECIALIZED | SYNCHRONIZED
+
/** When a symbol for a field is created, only these flags survive
* from Modifiers. Others which may be applied at creation time are:
* PRIVATE, LOCAL.
*/
- final val FieldFlags: Long =
+ final val FieldFlags =
MUTABLE | CASEACCESSOR | PARAMACCESSOR | STATIC | FINAL | PRESUPER | LAZY
/** Masks for getters and setters, where the flags are derived from those
@@ -247,24 +262,23 @@ class Flags extends ModifierFlags {
* flags from the method with the default. Other flags applied at creation
* time are SYNTHETIC, DEFAULTPARAM, and possibly OVERRIDE.
*/
- final val DefaultGetterFlags: Long =
- PRIVATE | PROTECTED | FINAL
+ final val DefaultGetterFlags = PRIVATE | PROTECTED | FINAL
/** When a symbol for a method parameter is created, only these flags survive
* from Modifiers. Others which may be applied at creation time are:
* SYNTHETIC.
*/
- final val ValueParameterFlags: Long = BYNAMEPARAM | IMPLICIT | DEFAULTPARAM
- final val BeanPropertyFlags = DEFERRED | OVERRIDE | STATIC
- final val VarianceFlags = COVARIANT | CONTRAVARIANT
+ final val ValueParameterFlags = BYNAMEPARAM | IMPLICIT | DEFAULTPARAM
+ final val BeanPropertyFlags = DEFERRED | OVERRIDE | STATIC
+ final val VarianceFlags = COVARIANT | CONTRAVARIANT
/** These appear to be flags which should be transferred from owner symbol
* to a newly created constructor symbol.
*/
- final val ConstrFlags: Long = JAVA
+ final val ConstrFlags = JAVA
/** Module flags inherited by their module-class */
- final val ModuleToClassFlags: Long = AccessFlags | MODULE | PACKAGE | CASE | SYNTHETIC | JAVA | FINAL
+ final val ModuleToClassFlags = AccessFlags | TopLevelCreationFlags | CASE | SYNTHETIC
def getterFlags(fieldFlags: Long): Long = ACCESSOR + (
if ((fieldFlags & MUTABLE) != 0) fieldFlags & ~MUTABLE & ~PRESUPER
@@ -294,7 +308,7 @@ class Flags extends ModifierFlags {
private final val PKL_MASK = 0x00000FFF
- final val PickledFlags: Long = 0xFFFFFFFFL
+ final val PickledFlags = 0xFFFFFFFFL
private def rawPickledCorrespondence = Array(
(IMPLICIT, IMPLICIT_PKL),
@@ -406,32 +420,28 @@ class Flags extends ModifierFlags {
case 0x8000000000000000L => "" // (1L << 63)
case _ => ""
}
-
+
+ private def accessString(flags: Long, privateWithin: String)= (
+ if (privateWithin == "") {
+ if ((flags & PrivateLocal) == PrivateLocal) "private[this]"
+ else if ((flags & ProtectedLocal) == ProtectedLocal) "protected[this]"
+ else if ((flags & PRIVATE) != 0) "private"
+ else if ((flags & PROTECTED) != 0) "protected"
+ else ""
+ }
+ else if ((flags & PROTECTED) != 0) "protected[" + privateWithin + "]"
+ else "private[" + privateWithin + "]"
+ )
+
+ @deprecated("Use flagString on the flag-carrying member", "2.10.0")
def flagsToString(flags: Long, privateWithin: String): String = {
- var f = flags
- val pw =
- if (privateWithin == "") {
- if ((flags & PrivateLocal) == PrivateLocal) {
- f &= ~PrivateLocal
- "private[this]"
- } else if ((flags & ProtectedLocal) == ProtectedLocal) {
- f &= ~ProtectedLocal
- "protected[this]"
- } else {
- ""
- }
- } else if ((f & PROTECTED) != 0L) {
- f &= ~PROTECTED
- "protected[" + privateWithin + "]"
- } else {
- "private[" + privateWithin + "]"
- }
- List(flagsToString(f), pw) filterNot (_ == "") mkString " "
- }
+ val access = accessString(flags, privateWithin)
+ val nonAccess = flagsToString(flags & ~AccessFlags)
- // List of the raw flags, in pickled order
- protected final val MaxBitPosition = 62
+ List(nonAccess, access) filterNot (_ == "") mkString " "
+ }
+ @deprecated("Use flagString on the flag-carrying member", "2.10.0")
def flagsToString(flags: Long): String = {
// Fast path for common case
if (flags == 0L) "" else {
@@ -459,13 +469,16 @@ class Flags extends ModifierFlags {
def pickledToRawFlags(pflags: Long): Long =
(pflags & ~PKL_MASK) | p2r(pflags.toInt & PKL_MASK)
- protected final val pickledListOrder: List[Long] = {
+ // List of the raw flags, in pickled order
+ final val MaxBitPosition = 62
+
+ final val pickledListOrder: List[Long] = {
val all = 0 to MaxBitPosition map (1L << _)
val front = rawFlags map (_.toLong)
front.toList ++ (all filterNot (front contains _))
}
- protected final val rawFlagPickledOrder: Array[Long] = pickledListOrder.toArray
+ final val rawFlagPickledOrder: Array[Long] = pickledListOrder.toArray
def flagOfModifier(mod: Modifier): Long = mod match {
case Modifier.`protected` => PROTECTED
diff --git a/src/compiler/scala/reflect/internal/FreeVars.scala b/src/compiler/scala/reflect/internal/FreeVars.scala
new file mode 100644
index 0000000000..8b6e8b61f3
--- /dev/null
+++ b/src/compiler/scala/reflect/internal/FreeVars.scala
@@ -0,0 +1,60 @@
+package scala.reflect
+package internal
+
+trait FreeVars extends api.FreeVars {
+ self: SymbolTable =>
+
+ object FreeTerm extends FreeTermExtractor {
+ def unapply(freeTerm: FreeTerm): Option[(TermName, Type, Any, String)] =
+ Some(freeTerm.name, freeTerm.info, freeTerm.value, freeTerm.origin)
+ }
+
+ object FreeType extends FreeTypeExtractor {
+ def unapply(freeType: FreeType): Option[(TypeName, Type, String)] =
+ Some(freeType.name, freeType.info, freeType.origin)
+ }
+
+ // [Eugene] am I doing this right?
+ def freeTerms(tree: Tree): List[FreeTerm] = {
+ def isFreeTermSym(sym: Symbol) = sym != null && sym.isFreeTerm
+ def isFreeTermTpe(t: Type) = t != null && isFreeTermSym(t.termSymbol)
+
+ val buf = collection.mutable.Set[Symbol]()
+ tree foreach (sub => {
+ if (sub.tpe != null) buf ++= (sub.tpe collect { case tpe if isFreeTermTpe(tpe) => tpe.typeSymbol })
+ if (sub.symbol != null && isFreeTermSym(sub.symbol)) buf += sub.symbol
+ })
+
+ buf.toList.collect{ case fty: FreeTerm => fty }
+ }
+
+ // [Eugene] am I doing this right?
+ def freeTypes(tree: Tree): List[FreeType] = {
+ def isFreeTypeSym(sym: Symbol) = sym != null && sym.isFreeType
+ def isFreeTypeTpe(t: Type) = t != null && isFreeTypeSym(t.typeSymbol)
+
+ val buf = collection.mutable.Set[Symbol]()
+ tree foreach (sub => {
+ if (sub.tpe != null) buf ++= (sub.tpe collect { case tpe if isFreeTypeTpe(tpe) => tpe.typeSymbol })
+ if (sub.symbol != null && isFreeTypeSym(sub.symbol)) buf += sub.symbol
+ })
+
+ buf.toList.collect{ case fty: FreeType => fty }
+ }
+
+ // todo. also update tpe's of dependent free vars
+ // e.g. if we substitute free$C, then free$C$this should have its info updated
+ // todo. should also transform typetags of types dependent on that free type?
+ // [Eugene] how do I check that the substitution is legal w.r.t fty.info?
+ def substituteFreeTypes(tree0: Tree, subs: Map[FreeType, Type]): Tree = {
+ val tree = tree0.duplicate
+ new TreeTypeSubstituter(subs.keys.toList, subs.values.toList).traverse(tree)
+ tree
+ }
+
+ // [Eugene] how do I check that the substitution is legal w.r.t fty.info?
+ def substituteFreeTypes(tpe0: Type, subs: Map[FreeType, Type]): Type = {
+ val tpe = tpe0 // [Eugene] tpe0.duplicate?
+ tpe.subst(subs.keys.toList, subs.values.toList)
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/internal/HasFlags.scala b/src/compiler/scala/reflect/internal/HasFlags.scala
index 8affd66cd5..348f81c51d 100644
--- a/src/compiler/scala/reflect/internal/HasFlags.scala
+++ b/src/compiler/scala/reflect/internal/HasFlags.scala
@@ -1,83 +1,12 @@
package scala.reflect
package internal
-/** ISSUE #1: Flag names vs. Test method names
- *
- * The following methods from Symbol have a name of
- * the form isFoo where FOO is the name of a flag, but where the method
- * body tests for more than whether the flag is set.
- *
- * There are two possibilities with such methods. Either the extra
- * tests are strictly to partition among overloaded flags (which is
- * the case we can live with in the short term, if each such flag's
- * partitioning assumptions are documented) or they aren't.
- *
- * The second case implies that "x hasFlag FOO" and "x.isFoo" have
- * different semantics, and this we can't live with, because even if
- * we're smart enough to avoid being tripped up by that, the next guy isn't.
- *
- * No extreme measures necessary, only renaming isFoo to something
- * which hews more closely to its implementation. (Or renaming the flag.)
- *
- // Defined in the compiler Symbol
- //
- final def isLabel = isMethod && !hasAccessorFlag && hasFlag(LABEL)
- final def isLocal: Boolean = owner.isTerm
- final def isModuleVar: Boolean = isVariable && hasFlag(MODULEVAR)
- final def isStable =
- isTerm &&
- !hasTraitFlag &&
- (!hasFlag(METHOD | BYNAMEPARAM) || hasFlag(STABLE)) &&
- !(tpe.isVolatile && !hasAnnotation(uncheckedStableClass))
- final def isStatic: Boolean =
- hasFlag(STATIC) || isRoot || owner.isStaticOwner
- override final def isTrait: Boolean =
- isClass && hasFlag(TRAIT | notDEFERRED) // A virtual class becomes a trait (part of DEVIRTUALIZE)
-
- // Defined in the library Symbol
- //
- def isTrait: Boolean = isClass && hasFlag(TRAIT) // refined later for virtual classes.
- final def isContravariant = isType && hasFlag(CONTRAVARIANT)
- final def isCovariant = isType && hasFlag(COVARIANT)
- final def isMethod = isTerm && hasFlag(METHOD)
- final def isModule = isTerm && hasFlag(MODULE)
- final def isPackage = isModule && hasFlag(PACKAGE)
- *
- */
-
-/** ISSUE #2: Implicit flag relationships must be made explicit.
- *
- * For instance, every time the MODULE flag is set, the FINAL flag is
- * set along with it:
- *
- .setFlag(FINAL | MODULE | PACKAGE | JAVA)
- .setFlag(FINAL | MODULE | PACKAGE | JAVA).setInfo(rootLoader)
- new ModuleSymbol(this, pos, name).setFlag(MODULE | FINAL)
- new ModuleSymbol(this, pos, name).setFlag(MODULE | FINAL)
- val m = new ModuleSymbol(this, pos, name).setFlag(MODULE | FINAL)
- setFlag(module.getFlag(ModuleToClassFlags) | MODULE | FINAL)
- sourceModule.flags = MODULE | FINAL
-
- * However the same is not true of when the MODULE flag is cleared:
-
- sym.resetFlag(MODULE)
- .setFlag(sym.flags | STABLE).resetFlag(MODULE)
- sym.resetFlag(MODULE | FINAL | CASE)
-
- * It's not relevant whether this example poses any issues: we must
- * not tolerate these uncertainties. If the flags are to move together
- * then both setting and clearing have to be encapsulated. If there
- * is a useful and used distinction between the various permutations
- * of on and off, then it must be documented. It's the only way!
- */
-
import Flags._
/** Common code utilized by Modifiers (which carry the flags associated
* with Trees) and Symbol.
*/
trait HasFlags {
- type FlagsType
type AccessBoundaryType
type AnnotationType
@@ -86,12 +15,7 @@ trait HasFlags {
* flag methods through accessors and disallow raw flag manipulation.
* And after that, perhaps, on some magical day: a typesafe enumeration.
*/
- protected def flags: FlagsType
-
- /** The printable representation of this entity's flags and access boundary,
- * restricted to flags in the given mask.
- */
- def hasFlagsToString(mask: FlagsType): String
+ protected def flags: Long
/** Access level encoding: there are three scala flags (PRIVATE, PROTECTED,
* and LOCAL) which combine with value privateWithin (the "foo" in private[foo])
@@ -137,6 +61,23 @@ trait HasFlags {
*/
def hasNoFlags(mask: Long): Boolean = !hasFlag(mask)
+ /** The printable representation of this entity's flags and access boundary,
+ * restricted to flags in the given mask.
+ */
+ def flagString: String = flagString(flagMask)
+ def flagString(mask: Long): String = calculateFlagString(flags & mask)
+
+ /** The default mask determining which flags to display.
+ */
+ def flagMask: Long = AllFlags
+
+ /** The string representation of a single bit, seen from this
+ * flag carrying entity.
+ */
+ def resolveOverloadedFlag(flag: Long): String = Flags.flagToString(flag)
+
+ def privateWithinString = if (hasAccessBoundary) privateWithin.toString else ""
+
protected def isSetting(f: Long, mask: Long) = !hasFlag(f) && ((mask & f) != 0L)
protected def isClearing(f: Long, mask: Long) = hasFlag(f) && ((mask & f) != 0L)
@@ -165,26 +106,20 @@ trait HasFlags {
// which must have been a bug.
def isPublic = hasNoFlags(PRIVATE | PROTECTED) && !hasAccessBoundary
- // Renamed the Modifiers impl from isArgument.
- def isParameter = hasFlag(PARAM)
-
// Removed isClass qualification since the flag isn't overloaded and
// sym.isClass is enforced in Namers#validate.
def isSealed = hasFlag(SEALED)
// Removed !isClass qualification since the flag isn't overloaded.
- def isDeferred = hasFlag(DEFERRED )
+ def isDeferred = hasFlag(DEFERRED)
// Dropped isTerm condition because flag isn't overloaded.
def isAbstractOverride = hasFlag(ABSOVERRIDE)
def isAnyOverride = hasFlag(OVERRIDE | ABSOVERRIDE)
- def isDefaultInit = hasFlag(DEFAULTINIT)
// Disambiguating: DEFAULTPARAM, TRAIT
def hasDefault = hasAllFlags(DEFAULTPARAM | PARAM)
def isTrait = hasFlag(TRAIT) && !hasFlag(PARAM)
- def hasTraitFlag = hasFlag(TRAIT)
- def hasDefaultFlag = hasFlag(DEFAULTPARAM)
// Straightforwardly named accessors already being used differently.
// These names are most likely temporary.
@@ -193,16 +128,9 @@ trait HasFlags {
def hasLocalFlag = hasFlag(LOCAL)
def hasModuleFlag = hasFlag(MODULE)
def hasPackageFlag = hasFlag(PACKAGE)
- def hasPreSuperFlag = hasFlag(PRESUPER)
def hasStableFlag = hasFlag(STABLE)
def hasStaticFlag = hasFlag(STATIC)
- // Disambiguating: BYNAMEPARAM, CAPTURED, COVARIANT.
- def isByNameParam = hasAllFlags(BYNAMEPARAM | PARAM)
- // Nope, these aren't going to fly:
- // def isCapturedVariable = hasAllFlags(CAPTURED | MUTABLE)
- // def isCovariant = hasFlag(COVARIANT) && hasNoFlags(PARAM | MUTABLE)
-
// Disambiguating: LABEL, CONTRAVARIANT, INCONSTRUCTOR
def isLabel = hasAllFlags(LABEL | METHOD) && !hasAccessorFlag
// Cannot effectively disambiguate the others at this level.
@@ -212,23 +140,60 @@ trait HasFlags {
// Name
def isJavaDefined = hasFlag(JAVA)
- // Keeping some potentially ambiguous names around so as not to break
- // the rest of the world
+ def flagBitsToString(bits: Long): String = {
+ // Fast path for common case
+ if (bits == 0L) "" else {
+ var sb: StringBuilder = null
+ var i = 0
+ while (i <= MaxBitPosition) {
+ val flag = Flags.rawFlagPickledOrder(i)
+ if ((bits & flag) != 0L) {
+ val s = resolveOverloadedFlag(flag)
+ if (s.length > 0) {
+ if (sb eq null) sb = new StringBuilder append s
+ else if (sb.length == 0) sb append s
+ else sb append " " append s
+ }
+ }
+ i += 1
+ }
+ if (sb eq null) "" else sb.toString
+ }
+ }
+
+ def accessString: String = {
+ val pw = privateWithinString
+
+ if (pw == "") {
+ if (hasAllFlags(PrivateLocal)) "private[this]"
+ else if (hasAllFlags(ProtectedLocal)) "protected[this]"
+ else if (hasFlag(PRIVATE)) "private"
+ else if (hasFlag(PROTECTED)) "protected"
+ else ""
+ }
+ else if (hasFlag(PROTECTED)) "protected[" + pw + "]"
+ else "private[" + pw + "]"
+ }
+ protected def calculateFlagString(basis: Long): String = {
+ val access = accessString
+ val nonAccess = flagBitsToString(basis & ~AccessFlags)
+
+ if (access == "") nonAccess
+ else if (nonAccess == "") access
+ else nonAccess + " " + access
+ }
+
+ // Backward compat section
+ @deprecated( "Use isTrait", "2.10.0")
+ def hasTraitFlag = hasFlag(TRAIT)
+ @deprecated("Use hasDefault", "2.10.0")
+ def hasDefaultFlag = hasFlag(DEFAULTPARAM)
@deprecated("", "2.9.0")
def isAbstract = hasFlag(ABSTRACT)
- // Problematic:
- // ABSTRACT and DEFERRED too easy to confuse, and
- // ABSTRACT + OVERRIDE ==> ABSOVERRIDE adds to it.
- //
- // final def isAbstractClass = isClass && hasFlag(ABSTRACT)
- // def isAbstractType = false // to be overridden
-
- // Question:
- // Which name? All other flags are isFlag so it's probably a mistake to
- // vary from that, but isAccessor does sound like it includes the other
- // *ACCESSOR flags. Perhaps something like isSimpleAccessor.
- //
- // def isAccessor = hasFlag(ACCESSOR )
- // final def isGetterOrSetter = hasAccessorFlag
+ @deprecated("Use isValueParameter or isTypeParameter", "2.10.0")
+ def isParameter = hasFlag(PARAM)
+ @deprecated("Use flagString", "2.10.0")
+ def defaultFlagString = flagString
+ @deprecated("Use flagString(mask)", "2.10.0")
+ def hasFlagsToString(mask: Long): String = flagString(mask)
}
-
diff --git a/src/compiler/scala/reflect/internal/Importers.scala b/src/compiler/scala/reflect/internal/Importers.scala
index 04381937d1..ab5e19fca9 100644
--- a/src/compiler/scala/reflect/internal/Importers.scala
+++ b/src/compiler/scala/reflect/internal/Importers.scala
@@ -4,7 +4,24 @@ import scala.collection.mutable.WeakHashMap
trait Importers { self: SymbolTable =>
- abstract class Importer {
+ // [Eugene] possible to make this less cast-heavy?
+ def mkImporter(from0: api.Universe): Importer { val from: from0.type } = (
+ if (self eq from0) {
+ new Importer {
+ val from = from0
+ val reverse = this.asInstanceOf[from.Importer{ val from: self.type }]
+ def importSymbol(sym: from.Symbol) = sym.asInstanceOf[self.Symbol]
+ def importType(tpe: from.Type) = tpe.asInstanceOf[self.Type]
+ def importTree(tree: from.Tree) = tree.asInstanceOf[self.Tree]
+ }
+ } else {
+ // todo. fix this loophole
+ assert(from0.isInstanceOf[SymbolTable], "`from` should be an instance of scala.reflect.internal.SymbolTable")
+ new StandardImporter { val from = from0.asInstanceOf[SymbolTable] }
+ }
+ ).asInstanceOf[Importer { val from: from0.type }]
+
+ abstract class StandardImporter extends Importer {
val from: SymbolTable
@@ -24,13 +41,15 @@ trait Importers { self: SymbolTable =>
}
}
- object reverse extends from.Importer {
+ object reverse extends from.StandardImporter {
val from: self.type = self
- for ((fromsym, mysym) <- Importer.this.symMap) symMap += ((mysym, fromsym))
- for ((fromtpe, mytpe) <- Importer.this.tpeMap) tpeMap += ((mytpe, fromtpe))
+ for ((fromsym, mysym) <- StandardImporter.this.symMap) symMap += ((mysym, fromsym))
+ for ((fromtpe, mytpe) <- StandardImporter.this.tpeMap) tpeMap += ((mytpe, fromtpe))
}
- def importPosition(pos: from.Position): Position = NoPosition
+ // todo. careful import of positions
+ def importPosition(pos: from.Position): Position =
+ pos.asInstanceOf[Position]
def importSymbol(sym0: from.Symbol): Symbol = {
def doImport(sym: from.Symbol): Symbol = {
@@ -51,8 +70,10 @@ trait Importers { self: SymbolTable =>
linkReferenced(myowner.newMethod(myname, mypos, myflags), x, importSymbol)
case x: from.ModuleSymbol =>
linkReferenced(myowner.newModuleSymbol(myname, mypos, myflags), x, importSymbol)
- case x: from.FreeVar =>
- newFreeVar(importName(x.name).toTermName, importType(x.tpe), x.value, myflags)
+ case x: from.FreeTerm =>
+ newFreeTerm(importName(x.name).toTermName, importType(x.info), x.value, x.origin, myflags)
+ case x: from.FreeType =>
+ newFreeType(importName(x.name).toTypeName, importType(x.info), x.value, x.origin, myflags)
case x: from.TermSymbol =>
linkReferenced(myowner.newValue(myname, mypos, myflags), x, importSymbol)
case x: from.TypeSkolem =>
@@ -63,7 +84,7 @@ trait Importers { self: SymbolTable =>
}
myowner.newTypeSkolemSymbol(myname.toTypeName, origin, mypos, myflags)
case x: from.ModuleClassSymbol =>
- val mysym = myowner.newModuleClassSymbol(myname.toTypeName, mypos, myflags)
+ val mysym = myowner.newModuleClass(myname.toTypeName, mypos, myflags)
symMap(x) = mysym
mysym.sourceModule = importSymbol(x.sourceModule)
mysym
@@ -72,7 +93,7 @@ trait Importers { self: SymbolTable =>
symMap(x) = mysym
if (sym.thisSym != sym) {
mysym.typeOfThis = importType(sym.typeOfThis)
- mysym.thisSym.name = importName(sym.thisSym.name)
+ mysym.thisSym setName importName(sym.thisSym.name)
}
mysym
case x: from.TypeSymbol =>
@@ -109,14 +130,18 @@ trait Importers { self: SymbolTable =>
val owner = sym.owner
var scope = if (owner.isClass && !owner.isRefinementClass) owner.info else from.NoType
var existing = scope.decl(name)
- if (sym.isPackageClass || sym.isModuleClass) existing = existing.moduleClass
+ 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.isPackageClass || sym.isModuleClass) myexisting = importSymbol(sym.sourceModule).moduleClass
+ if (sym.isModuleClass)
+ myexisting = importSymbol(sym.sourceModule).moduleClass
+
if (!sym.isOverloaded && myexisting.isOverloaded) {
myexisting =
if (sym.isMethod) {
@@ -370,6 +395,8 @@ trait Importers { self: SymbolTable =>
case _ =>
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() =>
@@ -421,7 +448,7 @@ trait Importers { self: SymbolTable =>
def importIdent(tree: from.Ident): Ident = importTree(tree).asInstanceOf[Ident]
def importCaseDef(tree: from.CaseDef): CaseDef = importTree(tree).asInstanceOf[CaseDef]
def importConstant(constant: from.Constant): Constant = new Constant(constant.tag match {
- case ClassTag => importType(constant.value.asInstanceOf[from.Type])
+ case ClazzTag => importType(constant.value.asInstanceOf[from.Type])
case EnumTag => importSymbol(constant.value.asInstanceOf[from.Symbol])
case _ => constant.value
})
diff --git a/src/compiler/scala/reflect/internal/NameManglers.scala b/src/compiler/scala/reflect/internal/NameManglers.scala
index 48f21721da..ac22017569 100644
--- a/src/compiler/scala/reflect/internal/NameManglers.scala
+++ b/src/compiler/scala/reflect/internal/NameManglers.scala
@@ -128,12 +128,7 @@ trait NameManglers {
else name
)
- def macroMethodName(name: Name) = {
- val base = if (name.isTypeName) nme.TYPEkw else nme.DEFkw
- base append nme.MACRO append name
- }
-
- /** Return the original name and the types on which this name
+ /** Return the original name and the types on which this name
* is specialized. For example,
* {{{
* splitSpecializedName("foo$mIcD$sp") == ('foo', "I", "D")
@@ -179,9 +174,6 @@ trait NameManglers {
else name.toTermName
}
- // This isn't needed at the moment since I fixed $class$1 but
- // I expect it will be at some point.
- //
// def anonNumberSuffix(name: Name): Name = {
// ("" + name) lastIndexOf '$' match {
// case -1 => nme.EMPTY
@@ -192,6 +184,18 @@ trait NameManglers {
// }
// }
+ // If the name ends with $nn where nn are
+ // all digits, strip the $ and the digits.
+ // Otherwise return the argument.
+ def stripAnonNumberSuffix(name: Name): Name = {
+ var pos = name.length
+ while (pos > 0 && name(pos - 1).isDigit)
+ pos -= 1
+
+ if (pos <= 0 || pos == name.length || name(pos - 1) != '$') name
+ else name.subName(0, pos - 1)
+ }
+
def stripModuleSuffix(name: Name): Name = (
if (isModuleName(name)) name dropRight MODULE_SUFFIX_STRING.length else name
)
diff --git a/src/compiler/scala/reflect/internal/Positions.scala b/src/compiler/scala/reflect/internal/Positions.scala
index 78de8d0ff2..5ec2659098 100644
--- a/src/compiler/scala/reflect/internal/Positions.scala
+++ b/src/compiler/scala/reflect/internal/Positions.scala
@@ -3,9 +3,8 @@ package internal
trait Positions extends api.Positions { self: SymbolTable =>
- def focusPos(pos: Position): Position
- def isRangePos(pos: Position): Boolean
- def showPos(pos: Position): String
+ type Position = scala.tools.nsc.util.Position
+ val NoPosition = scala.tools.nsc.util.NoPosition
/** A position that wraps a set of trees.
* The point of the wrapping position is the point of the default position.
@@ -27,4 +26,37 @@ trait Positions extends api.Positions { self: SymbolTable =>
* to some of the nodes in `tree`.
*/
def ensureNonOverlapping(tree: Tree, others: List[Tree]) {}
+
+ trait PosAssigner extends Traverser {
+ var pos: Position
+ }
+ protected[this] lazy val posAssigner: PosAssigner = new DefaultPosAssigner
+
+ protected class DefaultPosAssigner extends PosAssigner {
+ var pos: Position = _
+ override def traverse(t: Tree) {
+ if (t eq EmptyTree) ()
+ else if (t.pos == NoPosition) {
+ t.setPos(pos)
+ super.traverse(t) // TODO: bug? shouldn't the traverse be outside of the if?
+ // @PP: it's pruning whenever it encounters a node with a
+ // position, which I interpret to mean that (in the author's
+ // mind at least) either the children of a positioned node will
+ // already be positioned, or the children of a positioned node
+ // do not merit positioning.
+ //
+ // Whatever the author's rationale, it does seem like a bad idea
+ // to press on through a positioned node to find unpositioned
+ // children beneath it and then to assign whatever happens to
+ // be in `pos` to such nodes. There are supposed to be some
+ // position invariants which I can't imagine surviving that.
+ }
+ }
+ }
+
+ def atPos[T <: Tree](pos: Position)(tree: T): T = {
+ posAssigner.pos = pos
+ posAssigner.traverse(tree)
+ tree
+ }
} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/internal/Reporters.scala b/src/compiler/scala/reflect/internal/Reporters.scala
new file mode 100644
index 0000000000..20d4a1d026
--- /dev/null
+++ b/src/compiler/scala/reflect/internal/Reporters.scala
@@ -0,0 +1,74 @@
+package scala.reflect
+package internal
+
+trait Reporters { self: SymbolTable =>
+
+ import self.{Reporter => ApiReporter}
+ import scala.tools.nsc.reporters._
+ import scala.tools.nsc.reporters.{Reporter => NscReporter}
+ import scala.tools.nsc.Settings
+
+ def mkConsoleReporter(minSeverity: Int = 1): ApiReporter = {
+ val settings = new Settings()
+ if (minSeverity <= 0) settings.verbose.value = true
+ if (minSeverity > 1) settings.nowarn.value = true
+ wrapNscReporter(new ConsoleReporter(settings))
+ }
+
+ abstract class ApiToNscReporterProxy(val apiReporter: ApiReporter) extends AbstractReporter {
+ import apiReporter.{Severity => ApiSeverity}
+ val API_INFO = apiReporter.INFO
+ val API_WARNING = apiReporter.WARNING
+ val API_ERROR = apiReporter.ERROR
+
+ type NscSeverity = Severity
+ val NSC_INFO = INFO
+ val NSC_WARNING = WARNING
+ val NSC_ERROR = ERROR
+
+ def display(pos: Position, msg: String, nscSeverity: NscSeverity): Unit =
+ apiReporter.log(pos, msg, nscSeverity match {
+ case NSC_INFO => API_INFO
+ case NSC_WARNING => API_WARNING
+ case NSC_ERROR => API_ERROR
+ })
+
+ def displayPrompt(): Unit =
+ apiReporter.interactive()
+ }
+
+ def wrapApiReporter(apiReporter: ApiReporter): NscReporter = new ApiToNscReporterProxy(apiReporter) {
+ val settings = new Settings()
+ settings.verbose.value = true
+ settings.nowarn.value = false
+ }
+
+ class NscToApiReporterProxy(val nscReporter: NscReporter) extends ApiReporter {
+ val API_INFO = INFO
+ val API_WARNING = WARNING
+ val API_ERROR = ERROR
+
+ def display(info: Info): Unit = info.severity match {
+ case API_INFO => nscReporter.info(info.pos, info.msg, false)
+ case API_WARNING => nscReporter.warning(info.pos, info.msg)
+ case API_ERROR => nscReporter.error(info.pos, info.msg)
+ }
+
+ def interactive(): Unit = nscReporter match {
+ case nscReporter: AbstractReporter => nscReporter.displayPrompt()
+ case _ => // do nothing
+ }
+
+ override def flush(): Unit = {
+ super.flush()
+ nscReporter.flush()
+ }
+
+ override def reset(): Unit = {
+ super.reset()
+ nscReporter.reset()
+ }
+ }
+
+ def wrapNscReporter(nscReporter: NscReporter): ApiReporter = new NscToApiReporterProxy(nscReporter)
+}
diff --git a/src/compiler/scala/reflect/internal/Required.scala b/src/compiler/scala/reflect/internal/Required.scala
index 1bf1a2e97e..ba6d65a306 100644
--- a/src/compiler/scala/reflect/internal/Required.scala
+++ b/src/compiler/scala/reflect/internal/Required.scala
@@ -12,8 +12,6 @@ trait Required { self: SymbolTable =>
def picklerPhase: Phase
- val gen: TreeGen { val global: Required.this.type }
-
def settings: MutableSettings
def forInteractive: Boolean
diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala
index e2c253628c..1666887133 100644
--- a/src/compiler/scala/reflect/internal/StdNames.scala
+++ b/src/compiler/scala/reflect/internal/StdNames.scala
@@ -44,6 +44,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
final val IMPLICITkw: TermName = kw("implicit")
final val IMPORTkw: TermName = kw("import")
final val LAZYkw: TermName = kw("lazy")
+ final val MACROkw: TermName = kw("macro")
final val MATCHkw: TermName = kw("match")
final val NEWkw: TermName = kw("new")
final val NULLkw: TermName = kw("null")
@@ -123,6 +124,9 @@ trait StdNames extends NameManglers { self: SymbolTable =>
final val List: NameType = "List"
final val Seq: NameType = "Seq"
final val Symbol: NameType = "Symbol"
+ final val ClassTag: NameType = "ClassTag"
+ final val TypeTag : NameType = "TypeTag"
+ final val ConcreteTypeTag: NameType = "ConcreteTypeTag"
// fictions we use as both types and terms
final val ERROR: NameType = "<error>"
@@ -140,10 +144,12 @@ trait StdNames extends NameManglers { self: SymbolTable =>
final val Any: NameType = "Any"
final val AnyVal: NameType = "AnyVal"
+ final val Expr: NameType = "Expr"
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"
@@ -185,32 +191,34 @@ trait StdNames extends NameManglers { self: SymbolTable =>
trait TermNames extends Keywords with CommonNames {
// Compiler internal names
- val EXPAND_SEPARATOR_STRING = "$$"
-
- val ANYNAME: NameType = "<anyname>"
- val CONSTRUCTOR: NameType = "<init>"
- val FAKE_LOCAL_THIS: NameType = "this$"
- val INITIALIZER: NameType = CONSTRUCTOR // Is this buying us something?
- val LAZY_LOCAL: NameType = "$lzy"
- val LOCAL_SUFFIX_STRING = " "
- val MACRO: NameType = "macro$"
- val MIRROR_PREFIX: NameType = "$mr."
- val MIRROR_SHORT: NameType = "$mr"
- val MIXIN_CONSTRUCTOR: NameType = "$init$"
- val MODULE_INSTANCE_FIELD: NameType = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$"
- val OUTER: NameType = "$outer"
- val OUTER_LOCAL: NameType = OUTER + LOCAL_SUFFIX_STRING // "$outer ", note the space
- val OUTER_SYNTH: NameType = "<outer>" // emitted by virtual pattern matcher, replaced by outer accessor in explicitouter
- val SELECTOR_DUMMY: NameType = "<unapply-selector>"
- val SELF: NameType = "$this"
- val SPECIALIZED_INSTANCE: NameType = "specInstance$"
- val STAR: NameType = "*"
- val THIS: NameType = "_$this"
-
- final val Nil: NameType = "Nil"
- final val Predef: NameType = "Predef"
- final val ScalaRunTime: NameType = "ScalaRunTime"
- final val Some: NameType = "Some"
+ val EXPAND_SEPARATOR_STRING = "$$"
+
+ val ANYNAME: NameType = "<anyname>"
+ val CONSTRUCTOR: NameType = "<init>"
+ val FAKE_LOCAL_THIS: NameType = "this$"
+ val INITIALIZER: NameType = CONSTRUCTOR // Is this buying us something?
+ val LAZY_LOCAL: NameType = "$lzy"
+ val LOCAL_SUFFIX_STRING = " "
+ val MIRROR_PREFIX: NameType = "$mr."
+ val MIRROR_SHORT: NameType = "$mr"
+ val MIRROR_FREE_PREFIX: NameType = "free$"
+ val MIRROR_FREE_THIS_SUFFIX: NameType = "$this"
+ val MIRROR_FREE_VALUE_SUFFIX: NameType = "$value"
+ val MIXIN_CONSTRUCTOR: NameType = "$init$"
+ val MODULE_INSTANCE_FIELD: NameType = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$"
+ val OUTER: NameType = "$outer"
+ val OUTER_LOCAL: NameType = OUTER + LOCAL_SUFFIX_STRING // "$outer ", note the space
+ val OUTER_SYNTH: NameType = "<outer>" // emitted by virtual pattern matcher, replaced by outer accessor in explicitouter
+ val SELECTOR_DUMMY: NameType = "<unapply-selector>"
+ val SELF: NameType = "$this"
+ val SPECIALIZED_INSTANCE: NameType = "specInstance$"
+ val STAR: NameType = "*"
+ val THIS: NameType = "_$this"
+
+ 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"
@@ -260,6 +268,8 @@ trait StdNames extends NameManglers { self: SymbolTable =>
case _ => newTermName("x$" + i)
}
+ // [Eugene to Paul] see comments in StandardNames.scala to find out why's this here
+ val QQQ = ???
val ??? = encode("???")
val wrapRefArray: NameType = "wrapRefArray"
@@ -275,12 +285,38 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val genericWrapArray: NameType = "genericWrapArray"
// Compiler utilized names
- // val productElementName: NameType = "productElementName"
+
+ val AnnotatedType: NameType = "AnnotatedType"
+ val AnnotationInfo: NameType = "AnnotationInfo"
+ val Any: NameType = "Any"
+ val AnyVal: NameType = "AnyVal"
+ val Apply: NameType = "Apply"
+ val ArrayAnnotArg: NameType = "ArrayAnnotArg"
+ val ConstantType: NameType = "ConstantType"
+ val EmptyPackage: NameType = "EmptyPackage"
+ val EmptyPackageClass: NameType = "EmptyPackageClass"
+ val Expr: NameType = "Expr"
val Ident: NameType = "Ident"
+ val Import: NameType = "Import"
+ val Literal: NameType = "Literal"
+ val LiteralAnnotArg: NameType = "LiteralAnnotArg"
+ val NestedAnnotArg: NameType = "NestedAnnotArg"
+ val NoPrefix: NameType = "NoPrefix"
+ val NoSymbol: NameType = "NoSymbol"
+ val Nothing: NameType = "Nothing"
+ val NoType: NameType = "NoType"
+ val Null: NameType = "Null"
+ val Object: NameType = "Object"
+ val RootPackage: NameType = "RootPackage"
+ val RootClass: NameType = "RootClass"
+ val Select: NameType = "Select"
val StringContext: NameType = "StringContext"
val This: NameType = "This"
val Tree : NameType = "Tree"
+ val Tuple2: NameType = "Tuple2"
val TYPE_ : NameType = "TYPE"
+ val TypeApply: NameType = "TypeApply"
+ val TypeRef: NameType = "TypeRef"
val TypeTree: NameType = "TypeTree"
val UNIT : NameType = "UNIT"
val add_ : NameType = "add"
@@ -311,6 +347,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val clone_ : NameType = if (forMSIL) "MemberwiseClone" else "clone" // sn.OClone causes checkinit failure
val conforms: NameType = "conforms"
val copy: NameType = "copy"
+ val definitions: NameType = "definitions"
val delayedInit: NameType = "delayedInit"
val delayedInitArg: NameType = "delayedInit$body"
val drop: NameType = "drop"
@@ -322,7 +359,9 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val equalsNumNum : NameType = "equalsNumNum"
val equalsNumObject : NameType = "equalsNumObject"
val equals_ : NameType = if (forMSIL) "Equals" else "equals"
+ val erasure: NameType = "erasure"
val error: NameType = "error"
+ val eval: NameType = "eval"
val ex: NameType = "ex"
val false_ : NameType = "false"
val filter: NameType = "filter"
@@ -330,7 +369,6 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val find_ : NameType = "find"
val flatMap: NameType = "flatMap"
val foreach: NameType = "foreach"
- val freeValue : NameType = "freeValue"
val genericArrayOps: NameType = "genericArrayOps"
val get: NameType = "get"
val getOrElse: NameType = "getOrElse"
@@ -339,6 +377,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val hash_ : NameType = "hash"
val head: NameType = "head"
val identity: NameType = "identity"
+ val info: NameType = "info"
val inlinedEquals: NameType = "inlinedEquals"
val isArray: NameType = "isArray"
val isDefinedAt: NameType = "isDefinedAt"
@@ -350,36 +389,54 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val lang: NameType = "lang"
val length: NameType = "length"
val lengthCompare: NameType = "lengthCompare"
- val lift_ : NameType = "lift"
- val macro_ : NameType = "macro"
val macroThis : NameType = "_this"
- val macroContext : NameType = "_context"
+ val macroContext : NameType = "c"
val main: NameType = "main"
+ val manifest: NameType = "manifest"
val map: NameType = "map"
+ val materializeClassTag: NameType = "materializeClassTag"
+ val materializeTypeTag: NameType = "materializeTypeTag"
+ val materializeConcreteTypeTag: NameType = "materializeConcreteTypeTag"
val mirror : NameType = "mirror"
+ val moduleClass : NameType = "moduleClass"
+ val name: NameType = "name"
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 nmeNewTermName: NameType = "newTermName"
+ val nmeNewTypeName: NameType = "newTypeName"
val next: NameType = "next"
val notifyAll_ : NameType = "notifyAll"
val notify_ : NameType = "notify"
val null_ : NameType = "null"
val ofDim: NameType = "ofDim"
+ val origin: NameType = "origin"
+ val prefix : NameType = "prefix"
val productArity: NameType = "productArity"
val productElement: NameType = "productElement"
val productIterator: NameType = "productIterator"
val productPrefix: NameType = "productPrefix"
val readResolve: NameType = "readResolve"
+ val reflect : NameType = "reflect"
+ val reify : NameType = "reify"
val runOrElse: NameType = "runOrElse"
val runtime: NameType = "runtime"
val sameElements: NameType = "sameElements"
val scala_ : NameType = "scala"
+ val selectOverloadedMethod: NameType = "selectOverloadedMethod"
+ val selectTerm: NameType = "selectTerm"
+ val selectType: NameType = "selectType"
val self: NameType = "self"
val setAccessible: NameType = "setAccessible"
val setAnnotations: NameType = "setAnnotations"
val setSymbol: NameType = "setSymbol"
val setType: NameType = "setType"
val setTypeSignature: NameType = "setTypeSignature"
+ val staticClass : NameType = "staticClass"
+ val staticModule : NameType = "staticModule"
val synchronized_ : NameType = "synchronized"
val tail: NameType = "tail"
val thisModuleType: NameType = "thisModuleType"
@@ -390,6 +447,8 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val toObjectArray : NameType = "toObjectArray"
val toSeq: NameType = "toSeq"
val toString_ : NameType = if (forMSIL) "ToString" else "toString"
+ val tpe : NameType = "tpe"
+ val tree : NameType = "tree"
val true_ : NameType = "true"
val typedProductIterator: NameType = "typedProductIterator"
val unapply: NameType = "unapply"
@@ -529,6 +588,9 @@ trait StdNames extends NameManglers { self: SymbolTable =>
def expandedName(name: TermName, base: Symbol, separator: String = EXPAND_SEPARATOR_STRING): TermName =
newTermNameCached(base.fullName('$') + separator + name)
+ def isModuleVarName(name: Name): Boolean =
+ stripAnonNumberSuffix(name) endsWith MODULE_VAR_SUFFIX
+
def moduleVarName(name: TermName): TermName =
newTermNameCached("" + name + MODULE_VAR_SUFFIX)
@@ -579,9 +641,14 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val ZOR = encode("||")
// unary operators
+ // [Eugene to Paul] see comments in StandardNames.scala to find out why's this here
+ val UNARY_TILDE = UNARY_~
val UNARY_~ = encode("unary_~")
+ val UNARY_PLUS = UNARY_+
val UNARY_+ = encode("unary_+")
+ val UNARY_MINUS = UNARY_-
val UNARY_- = encode("unary_-")
+ val UNARY_NOT = UNARY_!
val UNARY_! = encode("unary_!")
// Grouped here so Cleanup knows what tests to perform.
diff --git a/src/compiler/scala/reflect/internal/SymbolCreations.scala b/src/compiler/scala/reflect/internal/SymbolCreations.scala
new file mode 100644
index 0000000000..a1163b0f57
--- /dev/null
+++ b/src/compiler/scala/reflect/internal/SymbolCreations.scala
@@ -0,0 +1,113 @@
+ /* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.reflect
+package internal
+
+import scala.collection.{ mutable, immutable }
+import scala.collection.mutable.ListBuffer
+import util.Statistics._
+import Flags._
+import api.Modifier
+import scala.tools.util.StringOps.{ ojoin }
+
+trait SymbolCreations {
+ self: SymbolTable =>
+
+ import definitions._
+
+ /** Symbol creation interface, possibly better moved somewhere else.
+ * It'd be nice if we had virtual classes, but since we
+ * don't: these methods insulate the direct instantiation of the symbols
+ * (which may be overridden, e.g. in SynchronizedSymbols) from the
+ * enforcement of preconditions and choice of symbol constructor based
+ * on flags, which are (or should be) final so they can be reasoned about
+ * without lots of surprises.
+ */
+ trait SymbolCreatorInterface {
+ // Fallbacks; more precise creators should normally be called.
+ protected def createTermSymbol(name: TermName, pos: Position, newFlags: Long): TermSymbol
+ // This in fact does not exist anymore in the interests of better typed TypeSymbols.
+ // protected def createTypeSymbol(name: TypeName, pos: Position, newFlags: Long): TypeSymbol
+
+ // I believe all but rogue TypeSymbols are one of: ClassSymbol, AbstractTypeSymbol, AliasTypeSymbol, or TypeSkolem.
+ protected def createAbstractTypeSymbol(name: TypeName, pos: Position, newFlags: Long): AbstractTypeSymbol
+ protected def createAliasTypeSymbol(name: TypeName, pos: Position, newFlags: Long): AliasTypeSymbol
+ protected def createTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position, newFlags: Long): TypeSkolem
+ protected def createClassSymbol(name: TypeName, pos: Position, newFlags: Long): ClassSymbol
+
+ // More specific ClassSymbols.
+ // TODO - AnonymousClassSymbol.
+ // TODO maybe - PackageObjects, but that one cost me a lot of time when I tried it before
+ // because it broke reification some way I couldn't see.
+ protected def createModuleClassSymbol(name: TypeName, pos: Position, newFlags: Long): ModuleClassSymbol
+ protected def createPackageClassSymbol(name: TypeName, pos: Position, newFlags: Long): PackageClassSymbol
+ protected def createRefinementClassSymbol(pos: Position, newFlags: Long): RefinementClassSymbol
+ protected def createImplClassSymbol(name: TypeName, pos: Position, newFlags: Long): ClassSymbol
+ protected def createPackageObjectClassSymbol(pos: Position, newFlags: Long): PackageObjectClassSymbol
+
+ // Distinguished term categories include methods, modules, packages, package objects,
+ // value parameters, and values (including vals, vars, and lazy vals.)
+ protected def createMethodSymbol(name: TermName, pos: Position, newFlags: Long): MethodSymbol
+ protected def createModuleSymbol(name: TermName, pos: Position, newFlags: Long): ModuleSymbol
+ protected def createPackageSymbol(name: TermName, pos: Position, newFlags: Long): PackageSymbol
+
+ // TODO
+ // protected def createValueParameterSymbol(name: TermName, pos: Position, newFlags: Long): TermSymbol
+ // protected def createValueMemberSymbol(name: TermName, pos: Position, newFlags: Long): TermSymbol
+ }
+
+ trait SymbolCreator extends SymbolCreatorInterface {
+ self: Symbol =>
+
+ /*** Predictable symbol creation.
+ *
+ * newTermSymbol, newClassSymbol, and newNonClassSymbol all create symbols based
+ * only on the flags (for reconstruction after reification.) It would be nice to
+ * combine the last two into newTypeSymbol, but this requires some flag which allows us
+ * to distinguish classes and type aliases, which as yet does not exist.
+ *
+ * The fundamental flags used to determine which Symbol subclass to instantiate are:
+ * METHOD, PACKAGE, MODULE, PARAM, DEFERRED.
+ */
+ final def newTermSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol = {
+ if ((newFlags & METHOD) != 0)
+ createMethodSymbol(name, pos, newFlags)
+ else if ((newFlags & PACKAGE) != 0)
+ createPackageSymbol(name, pos, newFlags | PackageFlags)
+ else if ((newFlags & MODULE) != 0)
+ createModuleSymbol(name, pos, newFlags)
+ else if ((newFlags & PARAM) != 0)
+ createValueParameterSymbol(name, pos, newFlags)
+ else
+ createValueMemberSymbol(name, pos, newFlags)
+ }
+
+ final def newClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ClassSymbol = {
+ if (name == tpnme.REFINE_CLASS_NAME)
+ createRefinementClassSymbol(pos, newFlags)
+ else if ((newFlags & PACKAGE) != 0)
+ createPackageClassSymbol(name, pos, newFlags | PackageFlags)
+ else if (name == tpnme.PACKAGE)
+ createPackageObjectClassSymbol(pos, newFlags)
+ else if ((newFlags & MODULE) != 0)
+ createModuleClassSymbol(name, pos, newFlags)
+ else if ((newFlags & IMPLCLASS) != 0)
+ createImplClassSymbol(name, pos, newFlags)
+ else
+ createClassSymbol(name, pos, newFlags)
+ }
+
+ final def newNonClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): TypeSymbol = {
+ if ((newFlags & DEFERRED) != 0)
+ createAbstractTypeSymbol(name, pos, newFlags)
+ else
+ createAliasTypeSymbol(name, pos, newFlags)
+ }
+
+ def newTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): TypeSymbol =
+ newNonClassSymbol(name, pos, newFlags)
+ }
+}
diff --git a/src/compiler/scala/reflect/internal/SymbolFlags.scala b/src/compiler/scala/reflect/internal/SymbolFlags.scala
new file mode 100644
index 0000000000..febcec8c7c
--- /dev/null
+++ b/src/compiler/scala/reflect/internal/SymbolFlags.scala
@@ -0,0 +1,176 @@
+ /* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.reflect
+package internal
+
+import scala.collection.{ mutable, immutable }
+import scala.collection.mutable.ListBuffer
+import util.Statistics._
+import Flags._
+import api.Modifier
+import scala.tools.util.StringOps.{ ojoin }
+
+trait SymbolFlags {
+ self: SymbolTable =>
+
+ import definitions._
+
+ /** Not mixed in under normal conditions; a powerful debugging aid.
+ */
+ trait FlagVerifier extends Symbol {
+ private def assert0(cond: Boolean, message: => Any) {
+ if (!cond) {
+ Console.err.println("[flag verification failure]\n%s\n%s\n".format(atPhaseStackMessage, message))
+ (new Throwable).getStackTrace.take(13).drop(3).foreach(println)
+ println("")
+ }
+ }
+
+ protected def verifyChange(isAdd: Boolean, mask: Long, before: Long) {
+ val after = if (isAdd) before | mask else before & ~mask
+ val added = after & ~before
+ val removed = before & ~after
+ val ignored = mask & ~added & ~removed
+ val error = (
+ (added & OverloadedFlagsMask) != 0 || (removed & OverloadedFlagsMask) != 0
+ // || (ignored != 0)
+ )
+ val addString = if (added == 0) "" else "+(" + flagsToString(added) + ")"
+ val removeString = if (removed == 0) "" else "-(" + flagsToString(removed) + ")"
+ val changeString = if (added == 0 && removed == 0) "no change" else addString + " " + removeString
+
+ if (error) {
+ val templ = (
+ """| symbol: %s %s in %s
+ | call: %s(%s)
+ | flags: %s
+ | result: %s""".stripMargin
+ )
+
+ assert0(false, templ.format(
+ shortSymbolClass,
+ name.decode,
+ owner,
+ if (isAdd) "+" else "-",
+ flagsToString(mask),
+ flagsToString(before),
+ changeString
+ ))
+ }
+ }
+
+ protected def verifyFlags(what: String) {
+ assert0(this hasAllFlags alwaysHasFlags, symbolCreationString + "\n always=%s, what=%s\n".format(flagsToString(alwaysHasFlags), what))
+ if (this hasFlag neverHasFlags) {
+ val hasRaw = (rawflags & neverHasFlags) != 0
+ assert0(!hasRaw, symbolCreationString + "\n never=%s, what=%s".format(flagsToString(neverHasFlags), what))
+ }
+ }
+ abstract override def initFlags(mask: Long): this.type = {
+ super.initFlags(mask)
+ verifyFlags("initFlags(" + flagsToString(mask) + ")")
+ this
+ }
+ abstract override def setFlag(mask: Long): this.type = {
+ verifyChange(true, mask, rawflags)
+ super.setFlag(mask)
+ verifyFlags("setFlag(" + flagsToString(mask) + ")")
+ this
+ }
+ abstract override def resetFlag(mask: Long): this.type = {
+ verifyChange(false, mask, rawflags)
+ super.resetFlag(mask)
+ verifyFlags("resetFlag(" + flagsToString(mask) + ")")
+ this
+ }
+ abstract override def flags_=(fs: Long) {
+ if ((fs & ~rawflags) != 0)
+ verifyChange(true, fs & ~rawflags, rawflags)
+ if ((rawflags & ~fs) != 0)
+ verifyChange(false, rawflags & ~fs, rawflags)
+
+ super.flags_=(fs)
+ verifyFlags("flags_=(" + flagsToString(fs) + ")")
+ }
+ }
+
+ /** Flags which should always be present on a particular class of
+ * Symbol, and never be present on any others.
+ */
+ def AllDistinguishingFlags: Long = METHOD | MODULE | IMPLCLASS
+
+ /** A distinguishing flag is one which the mixing class must always
+ * have, and which no other symbol class is allowed to have.
+ */
+ trait DistinguishingFlag extends SymbolFlagLogic {
+ this: Symbol =>
+
+ def distinguishingFlag: Long
+ override protected def alwaysHasFlags = super.alwaysHasFlags | distinguishingFlag
+ override protected def neverHasFlags = super.neverHasFlags & ~distinguishingFlag
+ }
+
+ trait SymbolFlagLogic {
+ this: Symbol =>
+
+ // Forced for performance reasons to define all the flag manipulation
+ // methods alongside the field being manipulated.
+ def getFlag(mask: Long): Long
+ def hasFlag(mask: Long): Boolean
+ def hasAllFlags(mask: Long): Boolean
+ def setFlag(mask: Long): this.type
+ def resetFlag(mask: Long): this.type
+ def initFlags(mask: Long): this.type
+ def resetFlags(): Unit
+
+ protected def resolveOverloadedFlag(flag: Long): String
+ protected def calculateFlagString(basis: Long): String
+
+ protected def alwaysHasFlags: Long = 0L
+ protected def neverHasFlags: Long = AllDistinguishingFlags
+
+ def rawFlagString(mask: Long): String = calculateFlagString(rawflags & mask)
+ def rawFlagString: String = rawFlagString(flagMask)
+ def debugFlagString: String = flagString(AllFlags)
+
+ /** String representation of symbol's variance */
+ def varianceString: String =
+ if (variance == 1) "+"
+ else if (variance == -1) "-"
+ else ""
+
+ override def flagMask =
+ if (settings.debug.value && !isAbstractType) AllFlags
+ else if (owner.isRefinementClass) ExplicitFlags & ~OVERRIDE
+ else ExplicitFlags
+
+ // make the error message more googlable
+ def flagsExplanationString =
+ if (isGADTSkolem) " (this is a GADT skolem)"
+ else ""
+
+ /** If the given flag is set on this symbol, also set the corresponding
+ * notFLAG. For instance if flag is PRIVATE, the notPRIVATE flag will
+ * be set if PRIVATE is currently set.
+ */
+ final def setNotFlag(flag: Int) = if (hasFlag(flag)) setFlag((flag: @annotation.switch) match {
+ case PRIVATE => notPRIVATE
+ case PROTECTED => notPROTECTED
+ case OVERRIDE => notOVERRIDE
+ case _ => abort("setNotFlag on invalid flag: " + flag)
+ })
+
+ protected def shortSymbolClass = getClass.getName.split('.').last.stripPrefix("Symbols$")
+ def symbolCreationString: String = (
+ "%s%25s | %-40s | %s".format(
+ if (settings.uniqid.value) "%06d | ".format(id) else "",
+ shortSymbolClass,
+ name.decode + " in " + owner,
+ rawFlagString
+ )
+ )
+ }
+}
diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala
index 256c1a6ced..ffc8178528 100644
--- a/src/compiler/scala/reflect/internal/SymbolTable.scala
+++ b/src/compiler/scala/reflect/internal/SymbolTable.scala
@@ -13,7 +13,10 @@ import scala.tools.nsc.util.WeakHashSet
abstract class SymbolTable extends api.Universe
with Collections
with Names
+ with SymbolCreations
with Symbols
+ with SymbolFlags
+ with FreeVars
with Types
with Kinds
with ExistentialsAndSkolems
@@ -32,6 +35,9 @@ abstract class SymbolTable extends api.Universe
with TypeDebugging
with Importers
with Required
+ with TreeBuildUtil
+ with Reporters
+ with CapturedVariables
{
def rootLoader: LazyType
def log(msg: => AnyRef): Unit
@@ -62,6 +68,8 @@ abstract class SymbolTable extends api.Universe
result
}
+ /** Dump each symbol to stdout after shutdown.
+ */
final val traceSymbolActivity = sys.props contains "scalac.debug.syms"
object traceSymbols extends {
val global: SymbolTable.this.type = SymbolTable.this
@@ -98,6 +106,11 @@ abstract class SymbolTable extends api.Universe
final def atPhaseStack: List[Phase] = phStack
final def phase: Phase = ph
+ def atPhaseStackMessage = atPhaseStack match {
+ case Nil => ""
+ case ps => ps.reverseMap("->" + _).mkString("(", " ", ")")
+ }
+
final def phase_=(p: Phase) {
//System.out.println("setting phase to " + p)
assert((p ne null) && p != NoPhase, p)
@@ -149,7 +162,7 @@ abstract class SymbolTable extends api.Universe
try op
finally popPhase(saved)
}
-
+
/** Since when it is to be "at" a phase is inherently ambiguous,
* a couple unambiguously named methods.
@@ -211,7 +224,7 @@ abstract class SymbolTable extends api.Universe
def arrayToRepeated(tp: Type): Type = tp match {
case MethodType(params, rtpe) =>
val formals = tp.paramTypes
- assert(formals.last.typeSymbol == definitions.ArrayClass)
+ assert(formals.last.typeSymbol == definitions.ArrayClass, formals)
val method = params.last.owner
val elemtp = formals.last.typeArgs.head match {
case RefinedType(List(t1, t2), _) if (t1.typeSymbol.isAbstractType && t2.typeSymbol == definitions.ObjectClass) =>
@@ -219,8 +232,7 @@ abstract class SymbolTable extends api.Universe
case t =>
t
}
- val newParams = method.newSyntheticValueParams(
- formals.init :+ appliedType(definitions.JavaRepeatedParamClass.typeConstructor, List(elemtp)))
+ val newParams = method.newSyntheticValueParams(formals.init :+ definitions.javaRepeatedType(elemtp))
MethodType(newParams, rtpe)
case PolyType(tparams, rtpe) =>
PolyType(tparams, arrayToRepeated(rtpe))
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala
index b984383dd2..fc94e96acd 100644
--- a/src/compiler/scala/reflect/internal/Symbols.scala
+++ b/src/compiler/scala/reflect/internal/Symbols.scala
@@ -45,21 +45,31 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
m
}
- /** Create a new free variable. Its owner is NoSymbol.
+ /** Create a new free term. Its owner is NoSymbol.
*/
- def newFreeVar(name: TermName, tpe: Type, value: Any, newFlags: Long = 0L): FreeVar =
- new FreeVar(name, value) initFlags newFlags setInfo tpe
+ def newFreeTerm(name: TermName, info: Type, value: => Any, origin: String, newFlags: Long = 0L): FreeTerm =
+ new FreeTerm(name, value, origin) initFlags newFlags setInfo info
+
+ /** Create a new free type. Its owner is NoSymbol.
+ */
+ def newFreeType(name: TypeName, info: Type, value: => Any, origin: String, newFlags: Long = 0L): FreeType =
+ new FreeType(name, value, origin) initFlags newFlags setInfo info
/** The original owner of a class. Used by the backend to generate
* EnclosingMethod attributes.
*/
val originalOwner = perRunCaches.newMap[Symbol, Symbol]()
- abstract class AbsSymbolImpl extends AbsSymbol { this: Symbol =>
- def newNestedSymbol(name: Name, pos: Position, newFlags: Long) = name match {
+ abstract class AbsSymbolImpl extends AbsSymbol {
+ this: Symbol =>
+
+ def kind: String = kindString
+
+ def newNestedSymbol(name: Name, pos: Position, newFlags: Long, isClass: Boolean): Symbol = name match {
case n: TermName => newTermSymbol(n, pos, newFlags)
- case n: TypeName => newTypeSymbol(n, pos, newFlags)
+ case n: TypeName => if (isClass) newClassSymbol(n, pos, newFlags) else newNonClassSymbol(n, pos, newFlags)
}
+
def enclosingClass: Symbol = enclClass
def enclosingMethod: Symbol = enclMethod
def thisPrefix: Type = thisType
@@ -73,28 +83,105 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def setInternalFlags(flag: Long): this.type = { setFlag(flag); this }
def setTypeSignature(tpe: Type): this.type = { setInfo(tpe); this }
def setAnnotations(annots: AnnotationInfo*): this.type = { setAnnotations(annots.toList); this }
+
+ private def lastElemType(ts: Seq[Type]): Type = ts.last.normalize.typeArgs.head
+
+ private def formalTypes(formals: List[Type], nargs: Int): List[Type] = {
+ val formals1 = formals mapConserve {
+ case TypeRef(_, ByNameParamClass, List(arg)) => arg
+ case formal => formal
+ }
+ if (isVarArgTypes(formals1)) {
+ val ft = lastElemType(formals)
+ formals1.init ::: List.fill(nargs - (formals1.length - 1))(ft)
+ } else formals1
+ }
+
+ def resolveOverloaded(pre: Type, targs: Seq[Type], actuals: Seq[Type]): Symbol = {
+ def firstParams(tpe: Type): (List[Symbol], List[Type]) = tpe match {
+ case PolyType(tparams, restpe) =>
+ val (Nil, formals) = firstParams(restpe)
+ (tparams, formals)
+ case MethodType(params, _) =>
+ (Nil, params map (_.tpe))
+ case _ =>
+ (Nil, Nil)
+ }
+ def isApplicable(alt: Symbol, targs: List[Type], actuals: Seq[Type]) = {
+ def isApplicableType(tparams: List[Symbol], tpe: Type): Boolean = {
+ val (tparams, formals) = firstParams(pre memberType alt)
+ val formals1 = formalTypes(formals, actuals.length)
+ val actuals1 =
+ if (isVarArgTypes(actuals)) {
+ if (!isVarArgTypes(formals)) return false
+ actuals.init :+ lastElemType(actuals)
+ } else actuals
+ if (formals1.length != actuals1.length) return false
+
+ if (tparams.isEmpty) return (actuals1 corresponds formals1)(_ <:< _)
+
+ if (targs.length == tparams.length)
+ isApplicableType(List(), tpe.instantiateTypeParams(tparams, targs))
+ else if (targs.nonEmpty)
+ false
+ else {
+ val tvars = tparams map (TypeVar(_))
+ (actuals1 corresponds formals1) { (actual, formal) =>
+ val tp1 = actual.deconst.instantiateTypeParams(tparams, tvars)
+ val pt1 = actual.instantiateTypeParams(tparams, tvars)
+ tp1 <:< pt1
+ } &&
+ solve(tvars, tparams, List.fill(tparams.length)(COVARIANT), upper = false)
+ }
+ }
+ isApplicableType(List(), pre.memberType(alt))
+ }
+ def isAsGood(alt1: Symbol, alt2: Symbol): Boolean = {
+ alt1 == alt2 ||
+ alt2 == NoSymbol || {
+ val (tparams, formals) = firstParams(pre memberType alt1)
+ isApplicable(alt2, tparams map (_.tpe), formals)
+ }
+ }
+ assert(isOverloaded)
+ val applicables = alternatives filter (isApplicable(_, targs.toList, actuals))
+ def winner(alts: List[Symbol]) =
+ ((NoSymbol: Symbol) /: alts)((best, alt) => if (isAsGood(alt, best)) alt else best)
+ val best = winner(applicables)
+ if (best == winner(applicables.reverse)) best else NoSymbol
+ }
}
/** The class for all symbols */
abstract class Symbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: Name)
extends AbsSymbolImpl
with HasFlags
+ with SymbolFlagLogic
+ with SymbolCreator
+ // with FlagVerifier // DEBUG
with Annotatable[Symbol] {
- type FlagsType = Long
type AccessBoundaryType = Symbol
type AnnotationType = AnnotationInfo
+ // TODO - don't allow names to be renamed in this unstructured a fashion.
+ // Rename as little as possible. Enforce invariants on all renames.
+ type NameType >: Null <: Name
+ type TypeOfClonedSymbol >: Null <: Symbol { type NameType = Symbol.this.NameType }
+
+ // Abstract here so TypeSymbol and TermSymbol can have a private[this] field
+ // with the proper specific type.
+ def rawname: NameType
+ def name: NameType
+ def name_=(n: Name): Unit
+ def asNameType(n: Name): NameType
+
private[this] var _rawowner = initOwner // Syncnote: need not be protected, as only assignment happens in owner_=, which is not exposed to api
- private[this] var _rawname = initName
- private[this] var _rawflags = 0L
+ private[this] var _rawflags: Long = _
def rawowner = _rawowner
- def rawname = _rawname
def rawflags = _rawflags
- protected def rawflags_=(x: FlagsType) { _rawflags = x }
-
private var rawpos = initPos
val id = nextId() // identity displayed when -uniqid
@@ -108,6 +195,18 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def pos = rawpos
def setPos(pos: Position): this.type = { this.rawpos = pos; this }
+ def setName(name: Name): this.type = { this.name = asNameType(name) ; this }
+
+ // Update the surrounding scopes
+ protected[this] def changeNameInOwners(name: Name) {
+ if (owner.isClass) {
+ var ifs = owner.infos
+ while (ifs != null) {
+ ifs.info.decls.rehash(this, name)
+ ifs = ifs.prev
+ }
+ }
+ }
/** !!! The logic after "hasFlag" is far too opaque to be unexplained.
* I'm guessing it's attempting to compensate for flag overloading,
@@ -135,7 +234,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def newLocalDummy(pos: Position) =
newTermSymbol(nme.localDummyName(this), pos) setInfo NoType
final def newMethod(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): MethodSymbol =
- newMethodSymbol(name, pos, METHOD | newFlags)
+ createMethodSymbol(name, pos, METHOD | newFlags)
final def newLabel(name: TermName, pos: Position = NoPosition): MethodSymbol =
newMethod(name, pos, LABEL)
@@ -146,73 +245,40 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** Static constructor with info set. */
def newStaticConstructor(pos: Position) =
newConstructor(pos, STATIC) setInfo UnitClass.tpe
+
/** Instance constructor with info set. */
def newClassConstructor(pos: Position) =
newConstructor(pos) setInfo MethodType(Nil, this.tpe)
- // Top-level objects can be automatically marked final, but others
- // must be explicitly marked final if overridable objects are enabled.
- private def ModuleFlags = (
- if (isPackage || !settings.overrideObjects.value) MODULE | FINAL
- else MODULE
- )
def newLinkedModule(clazz: Symbol, newFlags: Long = 0L): ModuleSymbol = {
- val m = newModuleSymbol(clazz.name.toTermName, clazz.pos, ModuleFlags | newFlags)
+ val m = newModuleSymbol(clazz.name.toTermName, clazz.pos, MODULE | newFlags)
connectModuleToClass(m, clazz.asInstanceOf[ClassSymbol])
}
final def newModule(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleSymbol = {
- val m = newModuleSymbol(name, pos, newFlags | ModuleFlags)
- val clazz = newModuleClassSymbol(name.toTypeName, pos, (m getFlag ModuleToClassFlags) | MODULE)
+ val m = newModuleSymbol(name, pos, newFlags | MODULE)
+ val clazz = newModuleClass(name.toTypeName, pos, m getFlag ModuleToClassFlags)
connectModuleToClass(m, clazz)
}
final def newPackage(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleSymbol = {
assert(name == nme.ROOT || isPackageClass, this)
- newModule(name, pos, JAVA | PACKAGE | newFlags)
+ newModule(name, pos, PackageFlags | newFlags)
}
- final def newThisSym(pos: Position) =
- newTermSymbol(nme.this_, pos, SYNTHETIC)
- final def newImport(pos: Position) =
- newTermSymbol(nme.IMPORT, pos)
- /** Direct symbol factories.
- * For internal use; these are unlikely to be what you want.
- */
- def newTermSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol =
- new TermSymbol(this, pos, name) initFlags newFlags
-
- def newAbstractTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AbstractTypeSymbol =
- new AbstractTypeSymbol(this, pos, name) initFlags newFlags
-
- def newAliasTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AliasTypeSymbol =
- new AliasTypeSymbol(this, pos, name) initFlags newFlags
+ final def newThisSym(name: TermName = nme.this_, pos: Position = NoPosition) =
+ newTermSymbol(name, pos, SYNTHETIC)
- def newModuleSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleSymbol =
- new ModuleSymbol(this, pos, name) initFlags newFlags
-
- def newMethodSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): MethodSymbol =
- new MethodSymbol(this, pos, name) initFlags newFlags
-
- def newClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ClassSymbol =
- new ClassSymbol(this, pos, name) initFlags newFlags
+ final def newImport(pos: Position) =
+ newTermSymbol(nme.IMPORT, pos)
- def newModuleClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleClassSymbol =
- new ModuleClassSymbol(this, pos, name) initFlags newFlags
+ final def newModuleSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleSymbol =
+ newTermSymbol(name, pos, newFlags).asInstanceOf[ModuleSymbol]
- /** Derive whether it is an abstract type from the flags; after creation
- * the DEFERRED flag will be ignored.
- */
- def newTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): TypeSymbol =
- if ((newFlags & DEFERRED) == 0L)
- newAliasTypeSymbol(name, pos, newFlags)
- else
- newAbstractTypeSymbol(name, pos, newFlags)
+ final def newModuleClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleClassSymbol =
+ newClassSymbol(name, pos, newFlags).asInstanceOf[ModuleClassSymbol]
- def newTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position = NoPosition, newFlags: Long = 0L): TypeSkolem =
- if ((newFlags & DEFERRED) == 0L)
- new TypeSkolem(this, pos, name, origin) initFlags newFlags
- else
- new TypeSkolem(this, pos, name, origin) with AbstractTypeMixin initFlags newFlags
+ final def newTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position = NoPosition, newFlags: Long = 0L): TypeSkolem =
+ createTypeSkolemSymbol(name, origin, pos, newFlags)
/** @param pre type relative to which alternatives are seen.
* for instance:
@@ -243,24 +309,29 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** Symbol of a type definition type T = ...
*/
final def newAliasType(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol =
- newAliasTypeSymbol(name, pos, newFlags)
+ createAliasTypeSymbol(name, pos, newFlags)
/** Symbol of an abstract type type T >: ... <: ...
*/
final def newAbstractType(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol =
- newAbstractTypeSymbol(name, pos, DEFERRED | newFlags)
+ createAbstractTypeSymbol(name, pos, DEFERRED | newFlags)
/** Symbol of a type parameter
*/
final def newTypeParameter(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L) =
newAbstractType(name, pos, PARAM | newFlags)
+ /** Symbol of an existential type T forSome { ... }
+ */
+ final def newExistential(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol =
+ newAbstractType(name, pos, EXISTENTIAL | newFlags)
+
/** Synthetic value parameters when parameter symbols are not available
*/
final def newSyntheticValueParamss(argtypess: List[List[Type]]): List[List[Symbol]] = {
var cnt = 0
def freshName() = { cnt += 1; nme.syntheticParamName(cnt) }
- mmap(argtypess)(tp => newValueParameter(freshName(), focusPos(owner.pos), SYNTHETIC) setInfo tp)
+ mmap(argtypess)(tp => newValueParameter(freshName(), owner.pos.focus, SYNTHETIC) setInfo tp)
}
def newSyntheticTypeParam(): Symbol = newSyntheticTypeParam("T0", 0L)
@@ -280,10 +351,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def newGADTSkolem(name: TypeName, origin: Symbol, info: Type): TypeSkolem =
newTypeSkolemSymbol(name, origin, origin.pos, origin.flags & ~(EXISTENTIAL | PARAM) | CASEACCESSOR | SYNTHETIC) setInfo info
-
- final def newExistential(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol =
- newAbstractType(name, pos, EXISTENTIAL | newFlags)
-
final def freshExistential(suffix: String): Symbol =
newExistential(freshExistentialName(suffix), pos)
@@ -318,23 +385,23 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def newErrorClass(name: TypeName) =
newClassWithInfo(name, Nil, new ErrorScope(this), pos, SYNTHETIC | IS_ERROR)
- final def newModuleClass(name: TypeName, pos: Position = NoPosition) =
- newModuleClassSymbol(name, pos)
+ final def newModuleClass(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L) =
+ newModuleClassSymbol(name, pos, newFlags | MODULE)
- final def newAnonymousClass(pos: Position) =
- newClassSymbol(tpnme.ANON_CLASS_NAME, pos)
-
- final def newAnonymousFunctionClass(pos: Position, newFlags: Long = 0L) =
+ final def newAnonymousFunctionClass(pos: Position = NoPosition, newFlags: Long = 0L) =
newClassSymbol(tpnme.ANON_FUN_NAME, pos, FINAL | SYNTHETIC | newFlags)
final def newAnonymousFunctionValue(pos: Position, newFlags: Long = 0L) =
newTermSymbol(nme.ANON_FUN_NAME, pos, SYNTHETIC | newFlags) setInfo NoType
+ def newImplClass(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ClassSymbol = {
+ newClassSymbol(name, pos, newFlags | IMPLCLASS)
+ }
+
/** Refinement types P { val x: String; type T <: Number }
* also have symbols, they are refinementClasses
*/
- final def newRefinementClass(pos: Position) =
- newClass(tpnme.REFINE_CLASS_NAME, pos)
+ final def newRefinementClass(pos: Position) = createRefinementClassSymbol(pos, 0L)
/** Create a new getter for current symbol (which must be a field)
*/
@@ -349,6 +416,18 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
case x: TermName => newErrorValue(x)
}
+ /** To overcome the crazy challenge of more specific types appearing
+ * in incoming positions. Don't need this much.
+ */
+ def asTypeSymbol: TypeSymbol = this match {
+ case x: TypeSymbol => x
+ case x => throw new FatalError(this + " is not a TypeSymbol")
+ }
+ def asTermSymbol: TermSymbol = this match {
+ case x: TermSymbol => x
+ case x => throw new FatalError(this + " is not a TermSymbol")
+ }
+
@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")
@@ -372,7 +451,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// True if the symbol is locked but still below the allowed recursion depth.
// False otherwise
private[scala] def lockOK: Boolean = {
- ((rawflags & LOCKED) == 0L) ||
+ ((_rawflags & LOCKED) == 0L) ||
((settings.Yrecursion.value != 0) &&
(recursionTable get this match {
case Some(n) => (n <= settings.Yrecursion.value)
@@ -381,7 +460,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// Lock a symbol, using the handler if the recursion depth becomes too great.
private[scala] def lock(handler: => Unit): Boolean = {
- if ((rawflags & LOCKED) != 0L) {
+ if ((_rawflags & LOCKED) != 0L) {
if (settings.Yrecursion.value != 0) {
recursionTable get this match {
case Some(n) =>
@@ -398,7 +477,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
} else { handler; false }
} else {
- rawflags |= LOCKED
+ _rawflags |= LOCKED
true
// activeLocks += 1
// lockedSyms += this
@@ -407,10 +486,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// Unlock a symbol
private[scala] def unlock() = {
- if ((rawflags & LOCKED) != 0L) {
+ if ((_rawflags & LOCKED) != 0L) {
// activeLocks -= 1
// lockedSyms -= this
- _rawflags = rawflags & ~LOCKED
+ _rawflags &= ~LOCKED
if (settings.Yrecursion.value != 0)
recursionTable -= this
}
@@ -418,42 +497,101 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// ----- tests ----------------------------------------------------------------------
- def isTerm = false // to be overridden
- def isType = false // to be overridden
- def isClass = false // to be overridden
- def isBottomClass = false // to be overridden
- def isAliasType = false // to be overridden
- def isAbstractType = false // to be overridden
- private[scala] def isSkolem = false // to be overridden
-
- /** Is this symbol a type but not a class? */
- def isNonClassType = false // to be overridden
-
- override final def isTrait = isClass && hasFlag(TRAIT)
- final def isAbstractClass = isClass && hasFlag(ABSTRACT)
- final def isBridge = hasFlag(BRIDGE)
- final def isContravariant = isType && hasFlag(CONTRAVARIANT)
- final def isConcreteClass = isClass && !hasFlag(ABSTRACT | TRAIT)
- final def isCovariant = isType && hasFlag(COVARIANT)
- final def isEarlyInitialized = isTerm && hasFlag(PRESUPER)
- final def isExistentiallyBound = isType && hasFlag(EXISTENTIAL)
- final def isImplClass = isClass && hasFlag(IMPLCLASS)
- final def isLazyAccessor = isLazy && lazyAccessor != NoSymbol
- final def isMethod = isTerm && hasFlag(METHOD)
- final def isModule = isTerm && hasFlag(MODULE)
- final def isModuleClass = isClass && hasFlag(MODULE)
- final def isNumericValueClass = definitions.isNumericValueClass(this)
- final def isOverloaded = hasFlag(OVERLOADED)
- final def isOverridableMember = !(isClass || isEffectivelyFinal) && owner.isClass
- final def isRefinementClass = isClass && name == tpnme.REFINE_CLASS_NAME
- final def isSourceMethod = isMethod && !hasFlag(STABLE) // exclude all accessors!!!
- final def isTypeParameter = isType && isParameter && !isSkolem
- final def isPrimitiveValueClass = definitions.isPrimitiveValueClass(this)
- final def isVarargsMethod = isMethod && hasFlag(VARARGS)
-
- /** Package tests */
- final def isPackage = isModule && hasFlag(PACKAGE)
- final def isPackageClass = isClass && hasFlag(PACKAGE)
+ /** All symbols are one of three categories: TermSymbol, TypeSymbol, or NoSymbol.
+ * There is only one NoSymbol.
+ */
+ def isTerm = false
+ def isType = false
+
+ /** TypeSymbols fall into four named direct subclasses:
+ * - ClassSymbol
+ * - AliasTypeSymbol
+ * - AbstractTypeSymbol
+ * - TypeSkolem
+ */
+ def isClass = false
+ def isAliasType = false
+ def isAbstractType = false
+ def isSkolem = false
+
+ /** A Type, but not a Class. */
+ def isNonClassType = false
+
+ /** The bottom classes are Nothing and Null, found in Definitions. */
+ def isBottomClass = false
+ def isSpecialized = this hasFlag SPECIALIZED
+
+ /** These are all tests for varieties of ClassSymbol, which has these subclasses:
+ * - ModuleClassSymbol
+ * - RefinementClassSymbol
+ * - PackageClassSymbol (extends ModuleClassSymbol)
+ */
+ def isAbstractClass = false
+ def isAnonOrRefinementClass = false
+ def isAnonymousClass = false
+ def isCaseClass = false
+ def isConcreteClass = false
+ def isImplClass = false // the implementation class of a trait
+ def isJavaInterface = false
+ def isModuleClass = false
+ def isNumericValueClass = false
+ def isPrimitiveValueClass = false
+ def isRefinementClass = false
+ override def isTrait = false
+
+ /** Qualities of Types, always false for TermSymbols.
+ */
+ def isContravariant = false
+ def isCovariant = false
+ def isExistentialQuantified = false
+ def isExistentialSkolem = false
+ def isExistentiallyBound = false
+ def isGADTSkolem = false
+ def isTypeParameter = false
+ def isTypeParameterOrSkolem = false
+ def isTypeSkolem = false
+ def isTypeMacro = false
+ def isFreeType = false
+
+ /** Qualities of Terms, always false for TypeSymbols.
+ */
+ def isAccessor = false
+ def isBridge = false
+ def isCapturedVariable = false
+ def isClassConstructor = false
+ def isConstructor = false
+ def isEarlyInitialized = false
+ def isGetter = false
+ def isLocalDummy = false
+ def isMixinConstructor = false
+ def isModule = false
+ def isOverloaded = false
+ def isSetter = false
+ def isSetterParameter = false
+ def isValue = false
+ def isValueParameter = false
+ def isVariable = false
+ override def hasDefault = false
+ def isTermMacro = false
+ def isFreeTerm = false
+
+ /** Qualities of MethodSymbols, always false for TypeSymbols
+ * and other TermSymbols.
+ */
+ def isCaseAccessorMethod = false
+ def isLiftedMethod = false
+ def isMethod = false
+ def isSourceMethod = false
+ def isVarargsMethod = false
+ override def isLabel = false
+
+ /** Package/package object tests */
+ def isPackage = false
+ def isPackageClass = false
+ def isPackageObject = false
+ def isPackageObjectClass = false
+ def isPackageObjectOrClass = isPackageObject || isPackageObjectClass
+ def isModuleOrModuleClass = isModule || isModuleClass
/** Overridden in custom objects in Definitions */
def isRoot = false
@@ -466,54 +604,64 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
def isEffectiveRoot = false
- /** For RootClass, EmptyPackageClass. For all other symbols, itself.
+ /** For RootClass, this is EmptyPackageClass. For all other symbols,
+ * the symbol itself.
*/
def ownerOfNewSymbols = this
+ final def isLazyAccessor = isLazy && lazyAccessor != NoSymbol
+ final def isOverridableMember = !(isClass || isEffectivelyFinal) && (this ne NoSymbol) && owner.isClass
+
/** Does this symbol denote a wrapper created by the repl? */
final def isInterpreterWrapper = (
- (isModule || isModuleClass)
+ (this hasFlag MODULE)
&& owner.isPackageClass
&& nme.isReplWrapperName(name)
)
+ @inline final override def getFlag(mask: Long): Long = flags & mask
+ /** Does symbol have ANY flag in `mask` set? */
+ @inline final override def hasFlag(mask: Long): Boolean = (flags & mask) != 0
+ /** Does symbol have ALL the flags in `mask` set? */
+ @inline final override def hasAllFlags(mask: Long): Boolean = (flags & mask) == mask
- /** Term symbols with the exception of static parts of Java classes and packages.
- */
- final def isValue = isTerm && !(isModule && hasFlag(PACKAGE | JAVA))
+ override def setFlag(mask: Long): this.type = { _rawflags |= mask ; this }
+ override def resetFlag(mask: Long): this.type = { _rawflags &= ~mask ; this }
+ override def resetFlags() { rawflags &= (TopLevelCreationFlags | alwaysHasFlags) }
- final def isVariable = isTerm && isMutable && !isMethod
+ /** Default implementation calls the generic string function, which
+ * will print overloaded flags as <flag1/flag2/flag3>. Subclasses
+ * of Symbol refine.
+ */
+ override def resolveOverloadedFlag(flag: Long): String = Flags.flagToString(flag)
- // interesting only for lambda lift. Captured variables are accessed from inner lambdas.
- final def isCapturedVariable = isVariable && hasFlag(CAPTURED)
+ /** Set the symbol's flags to the given value, asserting
+ * that the previous value was 0.
+ */
+ override def initFlags(mask: Long): this.type = {
+ assert(rawflags == 0L, symbolCreationString)
+ _rawflags = mask
+ this
+ }
- final def isGetter = isTerm && hasAccessorFlag && !nme.isSetterName(name)
- // todo: make independent of name, as this can be forged.
- final def isSetter = isTerm && hasAccessorFlag && nme.isSetterName(name)
- def isSetterParameter = isValueParameter && owner.isSetter
+ final def flags: Long = {
+ val fs = _rawflags & phase.flagMask
+ (fs | ((fs & LateFlags) >>> LateShift)) & ~(fs >>> AntiShift)
+ }
+ def flags_=(fs: Long) = _rawflags = fs
+ def rawflags_=(x: Long) { _rawflags = x }
final def hasGetter = isTerm && nme.isLocalName(name)
- final def isValueParameter = isTerm && hasFlag(PARAM)
- final def isLocalDummy = isTerm && nme.isLocalDummyName(name)
final def isInitializedToDefault = !isType && hasAllFlags(DEFAULTINIT | ACCESSOR)
- final def isClassConstructor = isTerm && (name == nme.CONSTRUCTOR)
- final def isMixinConstructor = isTerm && (name == nme.MIXIN_CONSTRUCTOR)
- final def isConstructor = isTerm && nme.isConstructorName(name)
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 isTypeParameterOrSkolem = isType && hasFlag(PARAM)
- final def isHigherOrderTypeParameter = (this ne NoSymbol) && owner.isTypeParameterOrSkolem
- final def isTypeSkolem = isSkolem && hasFlag(PARAM)
- // a type symbol bound by an existential type, for instance the T in
- // List[T] forSome { type T }
- final def isExistentialSkolem = isExistentiallyBound && isSkolem
- final def isExistentialQuantified = isExistentiallyBound && !isSkolem
- final def isGADTSkolem = isSkolem && hasFlag(CASEACCESSOR | SYNTHETIC)
+
+ def isHigherOrderTypeParameter = owner.isTypeParameterOrSkolem
// class C extends D( { class E { ... } ... } ). Here, E is a class local to a constructor
- final def isClassLocalToConstructor = isClass && hasFlag(INCONSTRUCTOR)
+ def isClassLocalToConstructor = false
final def isDerivedValueClass =
isClass && info.firstParent.typeSymbol == AnyValClass && !isPrimitiveValueClass
@@ -521,29 +669,26 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def isMethodWithExtension =
isMethod && owner.isDerivedValueClass && !isParamAccessor && !isConstructor && !hasFlag(SUPERACCESSOR)
- final def isAnonymousClass = isClass && (name containsName tpnme.ANON_CLASS_NAME)
- final def isAnonymousFunction = isSynthetic && (name containsName tpnme.ANON_FUN_NAME)
- final def isAnonOrRefinementClass = isAnonymousClass || isRefinementClass
-
- // A package object or its module class
- final def isPackageObjectOrClass = (this ne NoSymbol) && owner.isPackageClass && (name == nme.PACKAGE || name == tpnme.PACKAGE)
- final def isPackageObject = (this ne NoSymbol) && owner.isPackageClass && name == nme.PACKAGE
- final def isPackageObjectClass = (this ne NoSymbol) && owner.isPackageClass && name == tpnme.PACKAGE
-
+ final def isAnonymousFunction = isSynthetic && (name containsName tpnme.ANON_FUN_NAME)
final def isDefinedInPackage = effectiveOwner.isPackageClass
- final def isJavaInterface = isJavaDefined && isTrait
- final def needsFlatClasses = phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass
+ final def needsFlatClasses = phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass
+
+ /** change name by appending $$<fully-qualified-name-of-class `base`>
+ * Do the same for any accessed symbols or setters/getters.
+ * Implementation in TermSymbol.
+ */
+ def expandName(base: Symbol) { }
// In java.lang, Predef, or scala package/package object
def isInDefaultNamespace = UnqualifiedOwners(effectiveOwner)
/** The owner, skipping package objects.
*/
- def effectiveOwner = if (owner.isPackageObjectClass) owner.skipPackageObject else owner
+ def effectiveOwner = owner.skipPackageObject
/** If this is a package object or its implementing class, its owner: otherwise this.
*/
- final def skipPackageObject: Symbol = if (isPackageObjectOrClass) owner else this
+ def skipPackageObject: Symbol = this
/** If this is a constructor, its owner: otherwise this.
*/
@@ -614,22 +759,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
/** Does this symbol denote a stable value? */
- final def isStable =
- isTerm &&
- !isMutable &&
- (!hasFlag(METHOD | BYNAMEPARAM) || hasFlag(STABLE)) &&
- !(tpe.isVolatile && !hasAnnotation(uncheckedStableClass))
-
- // def isVirtualClass = hasFlag(DEFERRED) && isClass
- // def isVirtualTrait = hasFlag(DEFERRED) && isTrait
- def isLiftedMethod = isMethod && hasFlag(LIFTED)
- def isCaseClass = isClass && isCase
-
- // unfortunately having the CASEACCESSOR flag does not actually mean you
- // are a case accessor (you can also be a field.)
- def isCaseAccessorMethod = isMethod && isCaseAccessor
-
- def isMacro = isMethod && hasFlag(MACRO)
+ def isStable = false
/** Does this symbol denote the primary constructor of its enclosing class? */
final def isPrimaryConstructor =
@@ -644,23 +774,27 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
isMethod && isCase && isSynthetic
/** Is this symbol a trait which needs an implementation class? */
- final def needsImplClass: Boolean =
- isTrait && (!isInterface || hasFlag(lateINTERFACE)) && !isImplClass
+ final def needsImplClass = (
+ isTrait
+ && (!isInterface || hasFlag(lateINTERFACE))
+ && !isImplClass
+ )
/** Is this a symbol which exists only in the implementation class, not in its trait? */
- final def isImplOnly: Boolean =
- hasFlag(PRIVATE) ||
- (owner.isImplClass || owner.isTrait) &&
- ((hasFlag(notPRIVATE | LIFTED) && !hasFlag(ACCESSOR | SUPERACCESSOR | MODULE) || isConstructor) ||
- (hasFlag(LIFTED) && isModule && isMethod))
-
- /** Is this symbol a module variable?
- * This used to have to test for MUTABLE to distinguish the overloaded
- * MODULEVAR/SYNTHETICMETH flag, but now SYNTHETICMETH is gone.
- */
+ final def isImplOnly = isPrivate || (
+ (owner.isTrait || owner.isImplClass) && (
+ hasAllFlags(LIFTED | MODULE | METHOD)
+ || isConstructor
+ || hasFlag(notPRIVATE | LIFTED) && !hasFlag(ACCESSOR | SUPERACCESSOR | MODULE)
+ )
+ )
final def isModuleVar = hasFlag(MODULEVAR)
- /** Is this symbol static (i.e. with no outer instance)? */
+ /** Is this symbol static (i.e. with no outer instance)?
+ * Q: When exactly is a sym marked as STATIC?
+ * A: If it's a member of a toplevel object, or of an object contained in a toplevel object, or any number of levels deep.
+ * http://groups.google.com/group/scala-internals/browse_thread/thread/d385bcd60b08faf6
+ */
def isStatic = (this hasFlag STATIC) || owner.isStaticOwner
/** Is this symbol a static constructor? */
@@ -675,10 +809,12 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def isStaticOwner: Boolean =
isPackageClass || isModuleClass && isStatic
+ def isTopLevelModule = hasFlag(MODULE) && owner.isPackageClass
+
/** Is this symbol effectively final? I.e, it cannot be overridden */
final def isEffectivelyFinal: Boolean = (
- isFinal
- || hasModuleFlag && !settings.overrideObjects.value
+ (this hasFlag FINAL | PACKAGE)
+ || isModuleOrModuleClass && (owner.isPackageClass || !settings.overrideObjects.value)
|| isTerm && (
isPrivate
|| isLocal
@@ -693,7 +829,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def isConstant: Boolean = isStable && isConstantType(tpe.resultType)
/** Is this class nested in another class or module (not a package)? */
- def isNestedClass = isClass && !owner.isPackageClass
+ def isNestedClass = false
/** Is this class locally defined?
* A class is local, if
@@ -701,9 +837,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* - its owner is a value
* - it is defined within a local class
*/
- final def isLocalClass: Boolean =
- isClass && (isAnonOrRefinementClass || isLocal ||
- !owner.isPackageClass && owner.isLocalClass)
+ def isLocalClass = false
+
+ def isStableClass = false
/* code for fixing nested objects
override final def isModuleClass: Boolean =
@@ -738,25 +874,27 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// Does not always work if the rawInfo is a SourcefileLoader, see comment
// in "def coreClassesFirst" in Global.
- final def exists: Boolean =
- this != NoSymbol && (!owner.isPackageClass || { rawInfo.load(this); rawInfo != NoType })
+ def exists = !owner.isPackageClass || { rawInfo.load(this); rawInfo != NoType }
final def isInitialized: Boolean =
validTo != NoPeriod
- final def isStableClass: Boolean = {
- 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
- }
- def checkStable() =
- (info.baseClasses forall hasNoAbstractTypeMember) && { setFlag(STABLE); true }
- isClass && (hasFlag(STABLE) || checkStable())
+ // [Eugene] is this correct?
+ /** Determines whether this symbol can be loaded by subsequent reflective compilation */
+ final def isLocatable: Boolean = {
+ if (this == NoSymbol) return false
+ if (isRoot || isRootPackage) return true
+
+ if (!owner.isLocatable) return false
+ if (owner.isTerm) return false
+
+ if (isType && isNonClassType) return false
+ return true
}
+ // [Eugene] is it a good idea to add ``dealias'' to Symbol?
+ /** Expands type aliases */
+ def dealias: Symbol = this
/** The variance of this symbol as an integer */
final def variance: Int =
@@ -764,7 +902,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
else if (isContravariant) -1
else 0
-
/** The sequence number of this parameter symbol among all type
* and value parameters of symbol's owner. -1 if symbol does not
* appear among the parameters of its owner.
@@ -788,6 +925,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// ------ owner attribute --------------------------------------------------------------
def owner: Symbol = rawowner
+ // TODO - don't allow the owner to be changed without checking invariants, at least
+ // when under some flag. Define per-phase invariants for owner/owned relationships,
+ // e.g. after flatten all classes are owned by package classes, there are lots and
+ // lots of these to be declared (or more realistically, discovered.)
def owner_=(owner: Symbol) {
// don't keep the original owner in presentation compiler runs
// (the map will grow indefinitely, and the only use case is the
@@ -805,11 +946,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def ownerChain: List[Symbol] = this :: owner.ownerChain
def originalOwnerChain: List[Symbol] = this :: originalOwner.getOrElse(this, rawowner).originalOwnerChain
- def enclClassChain: List[Symbol] = {
- if ((this eq NoSymbol) || isPackageClass) Nil
- else if (isClass) this :: owner.enclClassChain
- else owner.enclClassChain
- }
+ // Non-classes skip self and return rest of owner chain; overridden in ClassSymbol.
+ def enclClassChain: List[Symbol] = owner.enclClassChain
def ownersIterator: Iterator[Symbol] = new Iterator[Symbol] {
private var current = Symbol.this
@@ -817,34 +955,17 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def next = { val r = current; current = current.owner; r }
}
- /** same as ownerChain contains sym, but more efficient, and
- * with a twist for refinement classes. A refinement class
- * has a transowner X if an of its parents has transowner X.
+ /** Same as `ownerChain contains sym` but more efficient, and
+ * with a twist for refinement classes (see RefinementClassSymbol.)
*/
def hasTransOwner(sym: Symbol): Boolean = {
var o = this
while ((o ne sym) && (o ne NoSymbol)) o = o.owner
- (o eq sym) ||
- isRefinementClass && (info.parents exists (_.typeSymbol.hasTransOwner(sym)))
+ (o eq sym)
}
// ------ name attribute --------------------------------------------------------------
- def name: Name = rawname
-
- def name_=(name: Name) {
- if (name != rawname) {
- if (owner.isClass) {
- var ifs = owner.infos
- while (ifs != null) {
- ifs.info.decls.rehash(this, name)
- ifs = ifs.prev
- }
- }
- _rawname = name
- }
- }
-
/** If this symbol has an expanded name, its original name, otherwise its name itself.
* @see expandName
*/
@@ -903,43 +1024,54 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
final def fullName: String = fullName('.')
-// ------ flags attribute --------------------------------------------------------------
+ /**
+ * Symbol creation implementations.
+ */
- final def flags: Long = {
- val fs = rawflags & phase.flagMask
- (fs | ((fs & LateFlags) >>> LateShift)) & ~(fs >>> AntiShift)
- }
- def flags_=(fs: Long) = _rawflags = fs
+ protected def createAbstractTypeSymbol(name: TypeName, pos: Position, newFlags: Long): AbstractTypeSymbol =
+ new AbstractTypeSymbol(this, pos, name) initFlags newFlags
- /** Set the symbol's flags to the given value, asserting
- * that the previous value was 0.
- */
- def initFlags(mask: Long): this.type = {
- assert(rawflags == 0L, this)
- _rawflags = mask
- this
- }
- def setFlag(mask: Long): this.type = { _rawflags = rawflags | mask ; this }
- def resetFlag(mask: Long): this.type = { _rawflags = rawflags & ~mask ; this }
- final def getFlag(mask: Long): Long = flags & mask
- final def resetFlags() { _rawflags = rawflags & TopLevelCreationFlags }
+ protected def createAliasTypeSymbol(name: TypeName, pos: Position, newFlags: Long): AliasTypeSymbol =
+ new AliasTypeSymbol(this, pos, name) initFlags newFlags
- /** Does symbol have ANY flag in `mask` set? */
- final def hasFlag(mask: Long): Boolean = (flags & mask) != 0L
+ protected def createTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position, newFlags: Long): TypeSkolem =
+ new TypeSkolem(this, pos, name, origin) initFlags newFlags
- /** Does symbol have ALL the flags in `mask` set? */
- final def hasAllFlags(mask: Long): Boolean = (flags & mask) == mask
+ protected def createClassSymbol(name: TypeName, pos: Position, newFlags: Long): ClassSymbol =
+ new ClassSymbol(this, pos, name) initFlags newFlags
- /** If the given flag is set on this symbol, also set the corresponding
- * notFLAG. For instance if flag is PRIVATE, the notPRIVATE flag will
- * be set if PRIVATE is currently set.
- */
- final def setNotFlag(flag: Int) = if (hasFlag(flag)) setFlag((flag: @annotation.switch) match {
- case PRIVATE => notPRIVATE
- case PROTECTED => notPROTECTED
- case OVERRIDE => notOVERRIDE
- case _ => abort("setNotFlag on invalid flag: " + flag)
- })
+ protected def createModuleClassSymbol(name: TypeName, pos: Position, newFlags: Long): ModuleClassSymbol =
+ new ModuleClassSymbol(this, pos, name) initFlags newFlags
+
+ protected def createPackageClassSymbol(name: TypeName, pos: Position, newFlags: Long): PackageClassSymbol =
+ new PackageClassSymbol(this, pos, name) initFlags newFlags
+
+ protected def createRefinementClassSymbol(pos: Position, newFlags: Long): RefinementClassSymbol =
+ new RefinementClassSymbol(this, pos) initFlags newFlags
+
+ protected def createPackageObjectClassSymbol(pos: Position, newFlags: Long): PackageObjectClassSymbol =
+ new PackageObjectClassSymbol(this, pos) initFlags newFlags
+
+ protected def createImplClassSymbol(name: TypeName, pos: Position, newFlags: Long): ClassSymbol =
+ new ClassSymbol(this, pos, name) with ImplClassSymbol initFlags newFlags
+
+ protected def createTermSymbol(name: TermName, pos: Position, newFlags: Long): TermSymbol =
+ new TermSymbol(this, pos, name) initFlags newFlags
+
+ protected def createMethodSymbol(name: TermName, pos: Position, newFlags: Long): MethodSymbol =
+ new MethodSymbol(this, pos, name) initFlags newFlags
+
+ protected def createModuleSymbol(name: TermName, pos: Position, newFlags: Long): ModuleSymbol =
+ new ModuleSymbol(this, pos, name) initFlags newFlags
+
+ protected def createPackageSymbol(name: TermName, pos: Position, newFlags: Long): PackageSymbol =
+ new PackageSymbol(this, pos, name) initFlags newFlags
+
+ protected def createValueParameterSymbol(name: TermName, pos: Position, newFlags: Long): TermSymbol =
+ new TermSymbol(this, pos, name) initFlags newFlags
+
+ protected def createValueMemberSymbol(name: TermName, pos: Position, newFlags: Long): TermSymbol =
+ new TermSymbol(this, pos, name) initFlags newFlags
/** The class or term up to which this symbol is accessible,
* or RootClass if it is public. As java protected statics are
@@ -1002,7 +1134,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
val tp = infos.info
//if (settings.debug.value) System.out.println("completing " + this.rawname + tp.getClass());//debug
- if ((rawflags & LOCKED) != 0L) { // rolled out once for performance
+ if ((_rawflags & LOCKED) != 0L) { // rolled out once for performance
lock {
setInfo(ErrorType)
throw CyclicReference(this, tp)
@@ -1200,9 +1332,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
var ph = phase
while (ph.prev.keepsTypeParams)
ph = ph.prev
- //
- // if (ph ne phase)
- // debuglog("checking unsafeTypeParams(" + this + ") at: " + phase + " reading at: " + ph)
ph
}
@@ -1234,7 +1363,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** The value parameter sections of this symbol.
*/
def paramss: List[List[Symbol]] = info.paramss
- def hasParamWhich(cond: Symbol => Boolean) = paramss exists (_ exists cond)
+ def hasParamWhich(cond: Symbol => Boolean) = mexists(paramss)(cond)
/** The least proper supertype of a class; includes all parent types
* and refinement where needed. You need to compute that in a situation like this:
@@ -1407,15 +1536,15 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// ------ cloneing -------------------------------------------------------------------
/** A clone of this symbol. */
- final def cloneSymbol: Symbol =
+ final def cloneSymbol: TypeOfClonedSymbol =
cloneSymbol(owner)
/** A clone of this symbol, but with given owner. */
- final def cloneSymbol(newOwner: Symbol): Symbol =
- cloneSymbol(newOwner, this.rawflags)
- final def cloneSymbol(newOwner: Symbol, newFlags: Long): Symbol =
- cloneSymbol(newOwner, newFlags, nme.NO_NAME)
- final def cloneSymbol(newOwner: Symbol, newFlags: Long, newName: Name): Symbol = {
+ final def cloneSymbol(newOwner: Symbol): TypeOfClonedSymbol =
+ cloneSymbol(newOwner, _rawflags)
+ final def cloneSymbol(newOwner: Symbol, newFlags: Long): TypeOfClonedSymbol =
+ cloneSymbol(newOwner, newFlags, null)
+ final def cloneSymbol(newOwner: Symbol, newFlags: Long, newName: Name): TypeOfClonedSymbol = {
val clone = cloneSymbolImpl(newOwner, newFlags)
( clone
setPrivateWithin privateWithin
@@ -1424,15 +1553,15 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
)
if (clone.thisSym != clone)
clone.typeOfThis = (clone.typeOfThis cloneInfo clone)
- if (newName != nme.NO_NAME)
- clone.name = newName
+
+ if (newName ne null)
+ clone setName asNameType(newName)
clone
}
/** Internal method to clone a symbol's implementation with the given flags and no info. */
- def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol
- def cloneSymbolImpl(owner: Symbol): Symbol = cloneSymbolImpl(owner, 0L)
+ def cloneSymbolImpl(owner: Symbol, newFlags: Long): TypeOfClonedSymbol
// ------ access to related symbols --------------------------------------------------
@@ -1443,14 +1572,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def enclMethod: Symbol = if (isSourceMethod) this else owner.enclMethod
/** The primary constructor of a class. */
- def primaryConstructor: Symbol = {
- var c = info.decl(
- if (isTrait || isImplClass) nme.MIXIN_CONSTRUCTOR
- else nme.CONSTRUCTOR)
- c = if (c hasFlag OVERLOADED) c.alternatives.head else c
- //assert(c != NoSymbol)
- c
- }
+ def primaryConstructor: Symbol = NoSymbol
/** The self symbol (a TermSymbol) of a class with explicit self type, or else the
* symbol itself (a TypeSymbol).
@@ -1560,13 +1682,12 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** The package class containing this symbol, or NoSymbol if there
* is not one. */
- def enclosingPackageClass: Symbol =
- if (this == NoSymbol) this else {
- var packSym = this.owner
- while (packSym != NoSymbol && !packSym.isPackageClass)
- packSym = packSym.owner
- packSym
- }
+ def enclosingPackageClass: Symbol = {
+ var packSym = this.owner
+ while (packSym != NoSymbol && !packSym.isPackageClass)
+ packSym = packSym.owner
+ packSym
+ }
/** The package containing this symbol, or NoSymbol if there
* is not one. */
@@ -1677,21 +1798,12 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* Note: does not work for classes owned by methods, see Namers.companionClassOf
*
* object Foo . companionClass --> class Foo
+ *
+ * !!! linkedClassOfClass depends on companionClass on the module class getting
+ * to the class. As presently implemented this potentially returns class for
+ * any symbol except NoSymbol.
*/
- final def companionClass: Symbol = {
- if (this != NoSymbol)
- flatOwnerInfo.decl(name.toTypeName).suchThat(_ isCoDefinedWith this)
- else NoSymbol
- }
-
- /** A helper method that factors the common code used the discover a
- * companion module of a class. If a companion module exists, its symbol is
- * returned, otherwise, `NoSymbol` is returned. The method assumes that
- * `this` symbol has already been checked to be a class (using `isClass`).
- */
- private final def companionModule0: Symbol =
- flatOwnerInfo.decl(name.toTermName).suchThat(
- sym => sym.hasFlag(MODULE) && (sym isCoDefinedWith this) && !sym.isMethod)
+ def companionClass: Symbol = flatOwnerInfo.decl(name.toTypeName).suchThat(_ isCoDefinedWith this)
/** For a class: the module or case class factory with the same name in the same package.
* For all others: NoSymbol
@@ -1699,9 +1811,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*
* class Foo . companionModule --> object Foo
*/
- final def companionModule: Symbol =
- if (isClass && !isRefinementClass) companionModule0
- else NoSymbol
+ def companionModule: Symbol = NoSymbol
/** For a module: its linked class
* For a plain class: its linked module or case factory.
@@ -1709,18 +1819,14 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*
* class Foo <-- companionSymbol --> object Foo
*/
- final def companionSymbol: Symbol =
- if (isTerm) companionClass
- else if (isClass) companionModule0
- else NoSymbol
+ def companionSymbol: Symbol = NoSymbol
/** For a module class: its linked class
* For a plain class: the module class of its linked module.
*
* class Foo <-- linkedClassOfClass --> class Foo$
*/
- final def linkedClassOfClass: Symbol =
- if (isModuleClass) companionClass else companionModule.moduleClass
+ def linkedClassOfClass: Symbol = NoSymbol
/**
* Returns the rawInfo of the owner. If the current phase has flat classes,
@@ -1733,7 +1839,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* symbol B in the decls of p. So to find a linked symbol ("object B" or "class B")
* we need to apply flatten to B first. Fixes #2470.
*/
- private final def flatOwnerInfo: Type = {
+ protected final def flatOwnerInfo: Type = {
if (needsFlatClasses)
info
owner.rawInfo
@@ -1747,18 +1853,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* This only works for implementation classes owned by other classes or traits.
* !!! Why?
*/
- final def toInterface: Symbol =
- if (isImplClass) {
- val result =
- if (phase.next.erasedTypes) {
- assert(!tpe.parents.isEmpty, this)
- tpe.parents.last.typeSymbol
- } else {
- owner.info.decl(nme.interfaceName(name))
- }
- assert(result != NoSymbol, this)
- result
- } else this
+ def toInterface: Symbol = this
/** The module class corresponding to this module.
*/
@@ -1912,23 +2007,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
case p :: _ => p
case _ => NoSymbol
}
-
- /** change name by appending $$<fully-qualified-name-of-class `base`>
- * Do the same for any accessed symbols or setters/getters
- */
- def expandName(base: Symbol) {
- if (this.isTerm && this != NoSymbol && !hasFlag(EXPANDEDNAME)) {
- setFlag(EXPANDEDNAME)
- if (hasAccessorFlag && !isDeferred) {
- accessed.expandName(base)
- } else if (hasGetter) {
- getter(owner).expandName(base)
- setter(owner).expandName(base)
- }
- name = nme.expandedName(name.toTermName, base)
- if (isType) name = name
- }
- }
/* code for fixing nested objects
def expandModuleClassName() {
name = newTypeName(name.toString + "$")
@@ -1953,7 +2031,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
def sealedDescendants: Set[Symbol] = children.flatMap(_.sealedDescendants) + this
- def orElse[T](alt: => Symbol): Symbol = if (this ne NoSymbol) this else alt
+ @inline final def orElse[T](alt: => Symbol): Symbol = if (this ne NoSymbol) this else alt
// ------ toString -------------------------------------------------------------------
@@ -1985,8 +2063,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
private case class SymbolKind(accurate: String, sanitized: String, abbreviation: String)
private def symbolKind: SymbolKind = {
- val kind =
- if (isInstanceOf[FreeVar]) ("free variable", "free variable", "FV")
+ var kind =
+ if (isTermMacro) ("macro method", "macro method", "MAC")
+ else if (isInstanceOf[FreeTerm]) ("free term", "free term", "FTE")
+ else if (isInstanceOf[FreeType]) ("free type", "free type", "FTY")
else if (isPackage) ("package", "package", "PK")
else if (isPackageClass) ("package class", "package", "PKC")
else if (isPackageObject) ("package object", "package", "PKO")
@@ -2007,6 +2087,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
else if (isSourceMethod) ("method", "method", "METH")
else if (isTerm) ("value", "value", "VAL")
else ("", "", "???")
+ if (isSkolem) kind = (kind._1, kind._2, kind._3 + "#SKO")
SymbolKind(kind._1, kind._2, kind._3)
}
@@ -2115,33 +2196,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def infosString = infos.toString
def debugLocationString = fullLocationString + " " + debugFlagString
- def debugFlagString = hasFlagsToString(-1L)
- def hasFlagsToString(mask: Long): String = flagsToString(
- flags & mask,
- if (hasAccessBoundary) privateWithin.toString else ""
- )
-
- /** String representation of symbol's variance */
- def varianceString: String =
- if (variance == 1) "+"
- else if (variance == -1) "-"
- else ""
-
- def defaultFlagMask =
- if (isAbstractType) ExplicitFlags
- else if (settings.debug.value) -1L
- else if (owner.isRefinementClass) ExplicitFlags & ~OVERRIDE
- else ExplicitFlags
-
- // make the error message more googlable
- def flagsExplanationString =
- if (isGADTSkolem) " (this is a GADT skolem)"
- else ""
- def accessString = hasFlagsToString(PRIVATE | PROTECTED | LOCAL)
- def defaultFlagString = hasFlagsToString(defaultFlagMask)
private def defStringCompose(infoString: String) = compose(
- defaultFlagString,
+ flagString,
keyString,
varianceString + nameString + infoString + flagsExplanationString
)
@@ -2171,19 +2228,81 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** A class for term symbols */
class TermSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TermName)
extends Symbol(initOwner, initPos, initName) {
+ private[this] var _referenced: Symbol = NoSymbol
+ privateWithin = NoSymbol
+
+ final type NameType = TermName
+ type TypeOfClonedSymbol = TermSymbol
+
+ private[this] var _rawname: TermName = initName
+ def rawname = _rawname
+ def name = _rawname
+ def name_=(name: Name) {
+ if (name != rawname) {
+ log("Renaming %s %s %s to %s".format(shortSymbolClass, debugFlagString, rawname, name))
+ changeNameInOwners(name)
+ _rawname = name.toTermName
+ }
+ }
+ final def asNameType(n: Name) = n.toTermName
+
final override def isTerm = true
- override def name: TermName = rawname.toTermName
- privateWithin = NoSymbol
+ /** Term symbols with the exception of static parts of Java classes and packages.
+ */
+ override def isValue = !(isModule && hasFlag(PACKAGE | JAVA))
+ override def isVariable = isMutable && !isMethod
+ override def isTermMacro = hasFlag(MACRO)
- private[this] var _referenced: Symbol = NoSymbol
+ // interesting only for lambda lift. Captured variables are accessed from inner lambdas.
+ override def isCapturedVariable = hasAllFlags(MUTABLE | CAPTURED) && !hasFlag(METHOD)
+
+ override def companionSymbol: Symbol = companionClass
+ override def moduleClass = if (isModule) referenced else NoSymbol
+
+ override def hasDefault = this hasFlag DEFAULTPARAM // overloaded with TRAIT
+ override def isBridge = this hasFlag BRIDGE
+ override def isEarlyInitialized = this hasFlag PRESUPER
+ override def isMethod = this hasFlag METHOD
+ override def isModule = this hasFlag MODULE
+ override def isOverloaded = this hasFlag OVERLOADED
+ override def isPackage = this hasFlag PACKAGE
+ override def isValueParameter = this hasFlag PARAM
+
+ override def isSetterParameter = isValueParameter && owner.isSetter
+ override def isAccessor = this hasFlag ACCESSOR
+ override def isGetter = isAccessor && !isSetter
+ override def isSetter = isAccessor && nme.isSetterName(name) // todo: make independent of name, as this can be forged.
+ override def isLocalDummy = nme.isLocalDummyName(name)
+ override def isClassConstructor = name == nme.CONSTRUCTOR
+ override def isMixinConstructor = name == nme.MIXIN_CONSTRUCTOR
+ override def isConstructor = nme.isConstructorName(name)
+
+ override def isPackageObject = isModule && (name == nme.PACKAGE)
+ override def isStable = !isUnstable
+ private def isUnstable = (
+ isMutable
+ || (hasFlag(METHOD | BYNAMEPARAM) && !hasFlag(STABLE))
+ || (tpe.isVolatile && !hasAnnotation(uncheckedStableClass))
+ )
+
+ // The name in comments is what it is being disambiguated from.
+ // TODO - rescue CAPTURED from BYNAMEPARAM so we can see all the names.
+ override def resolveOverloadedFlag(flag: Long) = flag match {
+ case DEFAULTPARAM => "<defaultparam>" // TRAIT
+ case MIXEDIN => "<mixedin>" // EXISTENTIAL
+ case LABEL => "<label>" // CONTRAVARIANT / INCONSTRUCTOR
+ case PRESUPER => "<presuper>" // IMPLCLASS
+ case BYNAMEPARAM => if (this.isValueParameter) "<bynameparam>" else "<captured>" // COVARIANT
+ case _ => super.resolveOverloadedFlag(flag)
+ }
def referenced: Symbol = _referenced
def referenced_=(x: Symbol) { _referenced = x }
def existentialBound = singletonBounds(this.tpe)
- def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol =
+ def cloneSymbolImpl(owner: Symbol, newFlags: Long): TermSymbol =
owner.newTermSymbol(name, pos, newFlags).copyAttrsFrom(this)
def copyAttrsFrom(original: TermSymbol): this.type = {
@@ -2207,14 +2326,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
override def outerSource: Symbol =
- if (name endsWith nme.OUTER) initialize.referenced
+ if (originalName == nme.OUTER) initialize.referenced
else NoSymbol
- override def moduleClass: Symbol =
- if (hasFlag(MODULE)) referenced else NoSymbol
-
def setModuleClass(clazz: Symbol): TermSymbol = {
- assert(hasFlag(MODULE), this)
+ assert(isModule, this)
referenced = clazz
this
}
@@ -2230,6 +2346,23 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
referenced
}
+ /** change name by appending $$<fully-qualified-name-of-class `base`>
+ * Do the same for any accessed symbols or setters/getters
+ */
+ override def expandName(base: Symbol) {
+ if (!hasFlag(EXPANDEDNAME)) {
+ setFlag(EXPANDEDNAME)
+ if (hasAccessorFlag && !isDeferred) {
+ accessed.expandName(base)
+ }
+ else if (hasGetter) {
+ getter(owner).expandName(base)
+ setter(owner).expandName(base)
+ }
+ name = nme.expandedName(name.toTermName, base)
+ }
+ }
+
protected def doCookJavaRawInfo() {
def cook(sym: Symbol) {
require(sym.isJavaDefined, sym)
@@ -2263,9 +2396,15 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** A class for module symbols */
class ModuleSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TermName)
- extends TermSymbol(initOwner, initPos, initName) {
+ extends TermSymbol(initOwner, initPos, initName) with DistinguishingFlag {
+ def distinguishingFlag = MODULE
private var flatname: TermName = null
+ override def isModule = true
+ override def moduleClass = referenced
+ override def companionClass =
+ flatOwnerInfo.decl(name.toTypeName).suchThat(_ isCoDefinedWith this)
+
override def owner = (
if (!isMethod && needsFlatClasses) rawowner.owner
else rawowner
@@ -2277,23 +2416,41 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
flatname
}
- else rawname.toTermName
+ else rawname
)
+ }
- override def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol =
- owner.newModuleSymbol(name, pos, newFlags).copyAttrsFrom(this)
+ class PackageSymbol protected[Symbols] (owner0: Symbol, pos0: Position, name0: TermName)
+ extends ModuleSymbol(owner0, pos0, name0) with DistinguishingFlag {
+ override def distinguishingFlag = super.distinguishingFlag | PACKAGE
+ override def isPackage = true
}
/** A class for method symbols */
class MethodSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TermName)
- extends TermSymbol(initOwner, initPos, initName) {
- private var mtpePeriod = NoPeriod
- private var mtpePre: Type = _
- private var mtpeResult: Type = _
- private var mtpeInfo: Type = _
-
- override def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol =
- owner.newMethodSymbol(name, pos, newFlags).copyAttrsFrom(this)
+ extends TermSymbol(initOwner, initPos, initName) with DistinguishingFlag {
+ def distinguishingFlag = METHOD
+ // MethodSymbols pick up MODULE when trait-owned object accessors are cloned
+ // during mixin composition.
+ override protected def neverHasFlags = super.neverHasFlags & ~MODULE
+
+ private[this] var mtpePeriod = NoPeriod
+ private[this] var mtpePre: Type = _
+ private[this] var mtpeResult: Type = _
+ private[this] var mtpeInfo: Type = _
+
+ override def isMethod = true
+ override def isLabel = this hasFlag LABEL
+ override def isVarargsMethod = this hasFlag VARARGS
+ override def isLiftedMethod = this hasFlag LIFTED
+
+ // TODO - this seems a strange definition for "isSourceMethod", given that
+ // it does not make any specific effort to exclude synthetics. Figure out what
+ // this method is really for and what logic makes sense.
+ override def isSourceMethod = !(this hasFlag STABLE) // exclude all accessors
+ // unfortunately having the CASEACCESSOR flag does not actually mean you
+ // are a case accessor (you can also be a field.)
+ override def isCaseAccessorMethod = isCaseAccessor
def typeAsMemberOf(pre: Type): Type = {
if (mtpePeriod == currentPeriod) {
@@ -2313,73 +2470,80 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
class AliasTypeSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName)
extends TypeSymbol(initOwner, initPos, initName) {
- // Temporary programmatic help tracking down who might do such a thing
- override def setFlag(mask: Long): this.type = {
- if (isSetting(DEFERRED, mask)) {
- println("Setting DEFERRED on alias at")
- (new Throwable).printStackTrace
- }
- super.setFlag(mask)
- }
+ type TypeOfClonedSymbol = TypeSymbol
final override def isAliasType = true
- override def cloneSymbolImpl(owner: Symbol, newFlags: Long): AliasTypeSymbol =
- owner.newAliasTypeSymbol(name, pos, newFlags)
- }
-
- class AbstractTypeSymbol(initOwner: Symbol, initPos: Position, initName: TypeName)
- extends TypeSymbol(initOwner, initPos, initName) with AbstractTypeMixin {
- override def cloneSymbolImpl(owner: Symbol, newFlags: Long): AbstractTypeSymbol =
- owner.newAbstractTypeSymbol(name, pos, newFlags)
+ final override def dealias = info.typeSymbol.dealias
+ override def cloneSymbolImpl(owner: Symbol, newFlags: Long): TypeSymbol =
+ owner.newNonClassSymbol(name, pos, newFlags)
}
- /** Might be mixed into TypeSymbol or TypeSkolem.
- */
- trait AbstractTypeMixin extends TypeSymbol {
- override def resetFlag(mask: Long): this.type = {
- // Temporary programmatic help tracking down who might do such a thing
- if (settings.debug.value) {
- if (isClearing(DEFERRED, mask)) {
- println("Clearing DEFERRED on abstract type at")
- (new Throwable).printStackTrace
- }
- }
- super.resetFlag(mask)
- }
+ class AbstractTypeSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName)
+ extends TypeSymbol(initOwner, initPos, initName) {
+ type TypeOfClonedSymbol = TypeSymbol
final override def isAbstractType = true
override def existentialBound = this.info
+ override def cloneSymbolImpl(owner: Symbol, newFlags: Long): TypeSymbol =
+ owner.newNonClassSymbol(name, pos, newFlags)
}
/** A class of type symbols. Alias and abstract types are direct instances
* of this class. Classes are instances of a subclass.
*/
- abstract class TypeSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName) extends Symbol(initOwner, initPos, initName) {
+ abstract class TypeSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName)
+ extends Symbol(initOwner, initPos, initName) {
privateWithin = NoSymbol
+ private[this] var _rawname: TypeName = initName
+
+ final type NameType = TypeName
+ type TypeOfClonedSymbol >: Null <: TypeSymbol
+ // cloneSymbolImpl still abstract in TypeSymbol.
+
+ def rawname = _rawname
+ def name = _rawname
+ final def asNameType(n: Name) = n.toTypeName
+
+ final override def isType = true
+ override def isNonClassType = true
+ override def isTypeMacro = hasFlag(MACRO)
+
+ override def resolveOverloadedFlag(flag: Long) = flag match {
+ case TRAIT => "<trait>" // DEFAULTPARAM
+ case EXISTENTIAL => "<existential>" // MIXEDIN
+ case COVARIANT => "<covariant>" // BYNAMEPARAM / CAPTURED
+ case CONTRAVARIANT => "<contravariant>" // LABEL / INCONSTRUCTOR (overridden again in ClassSymbol)
+ case _ => super.resolveOverloadedFlag(flag)
+ }
+
private var tyconCache: Type = null
private var tyconRunId = NoRunId
private var tpeCache: Type = _
private var tpePeriod = NoPeriod
+ override def isAbstractType = this hasFlag DEFERRED
+ override def isContravariant = this hasFlag CONTRAVARIANT
+ override def isCovariant = this hasFlag COVARIANT
+ override def isExistentialQuantified = isExistentiallyBound && !isSkolem
+ override def isExistentiallyBound = this hasFlag EXISTENTIAL
+ override def isTypeParameter = isTypeParameterOrSkolem && !isSkolem
+ override def isTypeParameterOrSkolem = this hasFlag PARAM
+
/** Overridden in subclasses for which it makes sense.
*/
def existentialBound: Type = abort("unexpected type: "+this.getClass+ " "+debugLocationString)
- override def name: TypeName = super.name.toTypeName
- final override def isType = true
- override def isNonClassType = true
- override def isAbstractType = {
- if (settings.debug.value) {
- if (isDeferred) {
- println("TypeSymbol claims to be abstract type: " + this.getClass + " " + debugFlagString + " at ")
- (new Throwable).printStackTrace
- }
+ // TODO - don't allow names to be renamed in this unstructured a fashion.
+ // Rename as little as possible. Enforce invariants on all renames.
+ def name_=(name: Name) {
+ if (name != rawname) {
+ log("Renaming %s %s %s to %s".format(shortSymbolClass, debugFlagString, rawname, name))
+ changeNameInOwners(name)
+ _rawname = name.toTypeName
}
- isDeferred
- }
- private def newTypeRef(targs: List[Type]) = {
- val pre = if (hasFlag(PARAM | EXISTENTIAL)) NoPrefix else owner.thisType
- typeRef(pre, this, targs)
}
+ 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
*
* {{{
@@ -2471,9 +2635,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
}
- def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol =
- owner.newTypeSymbol(name, pos, newFlags)
-
incCounter(typeSymbolCount)
}
@@ -2492,12 +2653,22 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
class TypeSkolem protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName, origin: AnyRef)
extends TypeSymbol(initOwner, initPos, initName) {
-
+ type TypeOfClonedSymbol = TypeSkolem
/** The skolemization level in place when the skolem was constructed */
val level = skolemizationLevel
final override def isSkolem = true
+ // a type symbol bound by an existential type, for instance the T in
+ // List[T] forSome { type T }
+ override def isExistentialSkolem = this hasFlag EXISTENTIAL
+ override def isGADTSkolem = this hasFlag CASEACCESSOR | SYNTHETIC
+ override def isTypeSkolem = this hasFlag PARAM
+ override def isAbstractType = this hasFlag DEFERRED
+
+ override def isExistentialQuantified = false
+ override def existentialBound = if (isAbstractType) this.info else super.existentialBound
+
/** If typeskolem comes from a type parameter, that parameter, otherwise skolem itself */
override def deSkolemize = origin match {
case s: Symbol => s
@@ -2510,7 +2681,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
//@M! (not deSkolemize.typeParams!!), also can't leave superclass definition: use info, not rawInfo
override def typeParams = info.typeParams
- override def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol =
+ override def cloneSymbolImpl(owner: Symbol, newFlags: Long): TypeSkolem =
owner.newTypeSkolemSymbol(name, origin, pos, newFlags)
override def nameString: String =
@@ -2521,17 +2692,109 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** A class for class symbols */
class ClassSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName)
extends TypeSymbol(initOwner, initPos, initName) {
- private[this] var flatname: TypeName = null
- private[this] var source: AbstractFileType = null
- private[this] var thissym: Symbol = this
+ type TypeOfClonedSymbol = ClassSymbol
+
+ private[this] var flatname: TypeName = _
+ private[this] var source: AbstractFileType = _
+ private[this] var thissym: Symbol = this
+
+ private[this] var thisTypeCache: Type = _
+ private[this] var thisTypePeriod = NoPeriod
+
+ override protected def alwaysHasFlags: Long = 0L
+ override protected def neverHasFlags: Long = 0L
+
+ override def resolveOverloadedFlag(flag: Long) = flag match {
+ case INCONSTRUCTOR => "<inconstructor>" // INCONSTRUCTOR / CONTRAVARIANT / LABEL
+ case EXISTENTIAL => "<existential>" // EXISTENTIAL / MIXEDIN
+ case IMPLCLASS => "<implclass>" // IMPLCLASS / PRESUPER
+ case _ => super.resolveOverloadedFlag(flag)
+ }
final override def isClass = true
final override def isNonClassType = false
final override def isAbstractType = false
final override def isAliasType = false
+ override def isAbstractClass = this hasFlag ABSTRACT
+ override def isCaseClass = this hasFlag CASE
+ override def isClassLocalToConstructor = this hasFlag INCONSTRUCTOR
+ override def isImplClass = this hasFlag IMPLCLASS
+ override def isModuleClass = this hasFlag MODULE
+ override def isPackageClass = this hasFlag PACKAGE
+ override def isTrait = this hasFlag TRAIT
+
+ override def isAnonOrRefinementClass = isAnonymousClass || isRefinementClass
+ override def isAnonymousClass = name containsName tpnme.ANON_CLASS_NAME
+ override def isConcreteClass = !(this hasFlag ABSTRACT | TRAIT)
+ override def isJavaInterface = hasAllFlags(JAVA | TRAIT)
+ override def isNestedClass = !owner.isPackageClass
+ override def isNumericValueClass = definitions.isNumericValueClass(this)
+ override def isPackageObjectClass = isModuleClass && (name == tpnme.PACKAGE)
+ override def isPrimitiveValueClass = definitions.isPrimitiveValueClass(this)
+
+ // The corresponding interface is the last parent by convention.
+ private def lastParent = if (tpe.parents.isEmpty) NoSymbol else tpe.parents.last.typeSymbol
+ override def toInterface: Symbol = (
+ if (isImplClass) {
+ if (phase.next.erasedTypes) lastParent
+ else owner.info.decl(nme.interfaceName(name))
+ }
+ else super.toInterface
+ )
+
+ /** Is this class locally defined?
+ * A class is local, if
+ * - it is anonymous, or
+ * - its owner is a value
+ * - it is defined within a local class
+ */
+ override def isLocalClass = (
+ isAnonOrRefinementClass
+ || isLocal
+ || !owner.isPackageClass && owner.isLocalClass
+ )
+ override def isStableClass = (this hasFlag STABLE) || checkStable()
+
+ private def checkStable() = {
+ def hasNoAbstractTypeMember(clazz: Symbol): Boolean =
+ (clazz hasFlag STABLE) || {
+ var e = clazz.info.decls.elems
+ while ((e ne null) && !(e.sym.isAbstractType && info.member(e.sym.name) == e.sym))
+ e = e.next
+ e == null
+ }
+ (info.baseClasses forall hasNoAbstractTypeMember) && {
+ setFlag(STABLE)
+ true
+ }
+ }
+
+ override def enclClassChain = this :: owner.enclClassChain
+
+ /** A helper method that factors the common code used the discover a
+ * companion module of a class. If a companion module exists, its symbol is
+ * returned, otherwise, `NoSymbol` is returned.
+ */
+ protected final def companionModule0: Symbol =
+ flatOwnerInfo.decl(name.toTermName).suchThat(
+ sym => sym.hasFlag(MODULE) && (sym isCoDefinedWith this) && !sym.isMethod)
+
+ override def companionModule = companionModule0
+ override def companionSymbol = companionModule0
+ override def linkedClassOfClass = companionModule.moduleClass
+
+ override def sourceModule = if (isModuleClass) companionModule else NoSymbol
+
override def existentialBound = GenPolyType(this.typeParams, TypeBounds.upper(this.classBound))
+ def primaryConstructorName = if (this hasFlag TRAIT | IMPLCLASS) nme.MIXIN_CONSTRUCTOR else nme.CONSTRUCTOR
+
+ override def primaryConstructor = {
+ val c = info decl primaryConstructorName
+ if (c.isOverloaded) c.alternatives.head else c
+ }
+
override def sourceFile =
if (owner.isPackageClass) source
else super.sourceFile
@@ -2542,12 +2805,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
thissym = this
}
- private var thisTypeCache: Type = _
- private var thisTypePeriod = NoPeriod
-
- private var typeOfThisCache: Type = _
- private var typeOfThisPeriod = NoPeriod
-
/** the type this.type in this class */
override def thisType: Type = {
val period = thisTypePeriod
@@ -2560,6 +2817,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def owner: Symbol =
if (needsFlatClasses) rawowner.owner else rawowner
+
override def name: TypeName = (
if (needsFlatClasses) {
if (flatname eq null)
@@ -2567,47 +2825,28 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
flatname
}
- else rawname.toTypeName
+ else rawname
)
/** A symbol carrying the self type of the class as its type */
override def thisSym: Symbol = thissym
- /** the self type of an object foo is foo.type, not class<foo>.this.type
- */
- override def typeOfThis: Type = {
- if (getFlag(MODULE | IMPLCLASS) == MODULE.toLong && owner != NoSymbol) {
- val period = typeOfThisPeriod
- if (period != currentPeriod) {
- typeOfThisPeriod = currentPeriod
- if (!isValid(period))
- typeOfThisCache = singleType(owner.thisType, sourceModule)
- }
- typeOfThisCache
- }
- else thisSym.tpe
- }
-
/** Sets the self type of the class */
override def typeOfThis_=(tp: Type) {
- thissym = newThisSym(pos).setInfo(tp)
+ thissym = newThisSym(nme.this_, pos).setInfo(tp)
}
- override def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol = {
+ override def cloneSymbolImpl(owner: Symbol, newFlags: Long): ClassSymbol = {
val clone = owner.newClassSymbol(name, pos, newFlags)
if (thisSym != this) {
clone.typeOfThis = typeOfThis
- clone.thisSym.name = thisSym.name
+ clone.thisSym setName thisSym.name
}
clone
}
- override def sourceModule =
- if (isModuleClass) companionModule else NoSymbol
-
override def firstParamAccessor =
- info.decls.find(m => (m hasFlag PARAMACCESSOR) && m.isMethod) getOrElse NoSymbol
-
+ info.decls.find(_ hasAllFlags PARAMACCESSOR | METHOD) getOrElse NoSymbol
private[this] var childSet: Set[Symbol] = Set()
override def children = childSet
@@ -2621,12 +2860,32 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* plain class symbols!
*/
class ModuleClassSymbol protected[Symbols] (owner: Symbol, pos: Position, name: TypeName)
- extends ClassSymbol(owner, pos, name) {
- private var module: Symbol = null
- private var implicitMembersCacheValue: List[Symbol] = List()
+ extends ClassSymbol(owner, pos, name) with DistinguishingFlag {
+ private[this] var module: Symbol = _
+ private[this] var typeOfThisCache: Type = _
+ private[this] var typeOfThisPeriod = NoPeriod
+
+ def distinguishingFlag = MODULE
+
+ private var implicitMembersCacheValue: List[Symbol] = Nil
private var implicitMembersCacheKey1: Type = NoType
private var implicitMembersCacheKey2: ScopeEntry = null
+ override def isModuleClass = true
+ override def linkedClassOfClass = companionClass
+
+ /** the self type of an object foo is foo.type, not class<foo>.this.type
+ */
+ override def typeOfThis = {
+ val period = typeOfThisPeriod
+ if (period != currentPeriod) {
+ typeOfThisPeriod = currentPeriod
+ if (!isValid(period))
+ typeOfThisCache = singleType(owner.thisType, sourceModule)
+ }
+ typeOfThisCache
+ }
+
def implicitMembers: List[Symbol] = {
val tp = info
if ((implicitMembersCacheKey1 ne tp) || (implicitMembersCacheKey2 ne tp.decls.elems)) {
@@ -2640,20 +2899,77 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
implicitMembersCacheValue
}
- override def sourceModule = module
+ // The null check seems to be necessary for the reifier.
+ override def sourceModule = if (module ne null) module else companionModule
override def sourceModule_=(module: Symbol) { this.module = module }
}
- class FreeVar(name0: TermName, val value: Any) extends TermSymbol(NoSymbol, NoPosition, name0) {
- override def hashCode = if (value == null) 0 else value.hashCode
- override def equals(other: Any): Boolean = other match {
- case that: FreeVar => this.value.asInstanceOf[AnyRef] eq that.value.asInstanceOf[AnyRef]
- case _ => false
+ class PackageObjectClassSymbol protected[Symbols] (owner0: Symbol, pos0: Position)
+ extends ModuleClassSymbol(owner0, pos0, tpnme.PACKAGE) {
+ final override def isPackageObjectClass = true
+ final override def isPackageObjectOrClass = true
+ final override def skipPackageObject = owner
+ final override def setName(name: Name): this.type = {
+ abort("Can't rename a package object to " + name)
+ }
+ }
+
+ trait ImplClassSymbol extends ClassSymbol {
+ override def sourceModule = companionModule
+ // override def isImplClass = true
+ override def typeOfThis = thisSym.tpe // don't use the ModuleClassSymbol typeOfThisCache.
+ }
+
+ class PackageClassSymbol protected[Symbols] (owner0: Symbol, pos0: Position, name0: TypeName)
+ extends ModuleClassSymbol(owner0, pos0, name0) with DistinguishingFlag {
+ override def distinguishingFlag = super.distinguishingFlag | PACKAGE
+ override def sourceModule = companionModule
+ override def enclClassChain = Nil
+ override def isPackageClass = true
+ }
+
+ class RefinementClassSymbol protected[Symbols] (owner0: Symbol, pos0: Position)
+ extends ClassSymbol(owner0, pos0, tpnme.REFINE_CLASS_NAME) {
+ override def name_=(name: Name) {
+ assert(false, "Cannot set name of RefinementClassSymbol to " + name)
+ super.name_=(name)
}
+ override def isRefinementClass = true
+ override def isAnonOrRefinementClass = true
+ override def isLocalClass = true
+ override def hasMeaninglessName = true
+ override def companionModule: Symbol = NoSymbol
+
+ /** The mentioned twist. A refinement class has transowner X
+ * if any of its parents has transowner X.
+ */
+ override def hasTransOwner(sym: Symbol) = (
+ super.hasTransOwner(sym)
+ || info.parents.exists(_.typeSymbol hasTransOwner sym)
+ )
+ }
+
+ class FreeTerm(name0: TermName, value0: => Any, val origin: String) extends TermSymbol(NoSymbol, NoPosition, name0) {
+ def value = value0
+ override def isFreeTerm = true
+ }
+
+ // [Eugene] the NoSymbol origin works for type parameters. what about existential free types?
+ class FreeType(name0: TypeName, value0: => Any, val origin: String) extends TypeSkolem(NoSymbol, NoPosition, name0, NoSymbol) {
+ def value = value0
+ override def isFreeType = true
}
/** An object representing a missing symbol */
class NoSymbol protected[Symbols]() extends Symbol(null, NoPosition, nme.NO_NAME) {
+ final type NameType = TermName
+ type TypeOfClonedSymbol = NoSymbol
+
+ def asNameType(n: Name) = n.toTermName
+ def rawname = nme.NO_NAME
+ def name = nme.NO_NAME
+ def name_=(n: Name) = abort("Cannot set NoSymbol's name to " + n)
+
synchronized {
setInfo(NoType)
privateWithin = this
@@ -2663,12 +2979,20 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
unlock()
validTo = currentPeriod
}
+ override def flagMask = AllFlags
+ override def exists = false
+ override def isHigherOrderTypeParameter = false
+ override def companionClass = NoSymbol
+ override def companionModule = NoSymbol
+ override def companionSymbol = NoSymbol
override def isSubClass(that: Symbol) = false
override def filter(cond: Symbol => Boolean) = this
override def defString: String = toString
override def locationString: String = ""
+ override def enclClassChain = Nil
override def enclClass: Symbol = this
override def enclosingTopLevelClass: Symbol = this
+ override def enclosingPackageClass: Symbol = this
override def enclMethod: Symbol = this
override def sourceFile: AbstractFileType = null
override def ownerChain: List[Symbol] = List()
@@ -2680,7 +3004,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def rawInfo: Type = NoType
protected def doCookJavaRawInfo() {}
override def accessBoundary(base: Symbol): Symbol = RootClass
- def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol = abort("NoSymbol.clone()")
+ def cloneSymbolImpl(owner: Symbol, newFlags: Long) = abort("NoSymbol.clone()")
override def originalEnclosingMethod = this
override def owner: Symbol =
@@ -2689,9 +3013,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
abort("no-symbol does not have a type constructor (this may indicate scalac cannot find fundamental classes)")
}
- protected def makeNoSymbol = new NoSymbol
+ protected def makeNoSymbol: NoSymbol = new NoSymbol
- lazy val NoSymbol = makeNoSymbol
+ lazy val NoSymbol: NoSymbol = makeNoSymbol
/** Derives a new list of symbols from the given list by mapping the given
* list across the given function. Then fixes the info of all the new symbols
@@ -2779,7 +3103,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** A class for type histories */
private sealed case class TypeHistory(var validFrom: Period, info: Type, prev: TypeHistory) {
assert((prev eq null) || phaseId(validFrom) > phaseId(prev.validFrom), this)
- assert(validFrom != NoPeriod)
+ assert(validFrom != NoPeriod, this)
+
override def toString() =
"TypeHistory(" + phaseOf(validFrom)+":"+runId(validFrom) + "," + info + "," + prev + ")"
diff --git a/src/compiler/scala/reflect/internal/TreeBuildUtil.scala b/src/compiler/scala/reflect/internal/TreeBuildUtil.scala
new file mode 100644
index 0000000000..fbcd5043bc
--- /dev/null
+++ b/src/compiler/scala/reflect/internal/TreeBuildUtil.scala
@@ -0,0 +1,62 @@
+package scala.reflect
+package internal
+
+trait TreeBuildUtil extends api.TreeBuildUtil { self: SymbolTable =>
+
+ // ``staticClass'' and ``staticModule'' rely on ClassLoaders
+ // which are implementation-specific for different Universes
+
+ def staticClassIfDefined(fullName: String): Symbol =
+ try staticClass(fullName)
+ catch { case _: MissingRequirementError => NoSymbol }
+
+ def staticModuleIfDefined(fullName: String): Symbol =
+ try staticModule(fullName)
+ catch { case _: MissingRequirementError => NoSymbol }
+
+ def thisModuleType(fullname: String) = staticModule(fullname).moduleClass.thisType
+
+ def selectType(owner: Symbol, name: String): Symbol =
+ owner.info.decl(newTypeName(name)) orElse {
+ MissingRequirementError.notFound("type %s in %s".format(name, owner.fullName))
+ }
+
+ def selectTypeIfDefined(owner: Symbol, name: String): Symbol =
+ try selectType(owner, name)
+ catch { case _: MissingRequirementError => NoSymbol }
+
+// try getModule(fullname.toTermName)
+// catch { case _: MissingRequirementError => NoSymbol }
+
+ def selectTerm(owner: Symbol, name: String): Symbol = {
+ val sym = owner.info.decl(newTermName(name))
+ val result =
+ if (sym.isOverloaded) sym suchThat (!_.isMethod)
+ else sym
+ result orElse {
+ MissingRequirementError.notFound("term %s in %s".format(name, owner.fullName))
+ }
+ }
+
+ def selectTermIfDefined(owner: Symbol, name: String): Symbol =
+ try selectTerm(owner, name)
+ catch { case _: MissingRequirementError => NoSymbol }
+
+ def selectOverloadedMethod(owner: Symbol, name: String, index: Int): Symbol =
+ owner.info.decl(newTermName(name)).alternatives(index) orElse {
+ MissingRequirementError.notFound("overloaded method %s #%d in %s".format(name, index, owner.fullName))
+ }
+
+ def selectOverloadedMethodIfDefined(owner: Symbol, name: String, index: Int): Symbol =
+ try selectOverloadedMethod(owner, name, index)
+ catch { case _: MissingRequirementError => NoSymbol }
+
+ def newFreeTerm(name: String, info: Type, value: => Any, origin: String) = newFreeTerm(newTermName(name), info, value, origin)
+
+ def newFreeType(name: String, info: Type, value: => Any, origin: String) = newFreeType(newTypeName(name), info, value, origin)
+
+ def modifiersFromInternalFlags(flags: Long, privateWithin: Name, annotations: List[Tree]): Modifiers =
+ Modifiers(flags, privateWithin, annotations)
+
+ val gen: TreeGen { val global: TreeBuildUtil.this.type }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/internal/TreeGen.scala b/src/compiler/scala/reflect/internal/TreeGen.scala
index 141ff12f8a..1a374b6e59 100644
--- a/src/compiler/scala/reflect/internal/TreeGen.scala
+++ b/src/compiler/scala/reflect/internal/TreeGen.scala
@@ -1,7 +1,7 @@
package scala.reflect
package internal
-abstract class TreeGen {
+abstract class TreeGen extends api.AbsTreeGen {
val global: SymbolTable
import global._
diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala
index ce3de94335..ed22cad730 100644
--- a/src/compiler/scala/reflect/internal/TreeInfo.scala
+++ b/src/compiler/scala/reflect/internal/TreeInfo.scala
@@ -531,4 +531,198 @@ abstract class TreeInfo {
case _ => None
}
}
+
+ // domain-specific extractors for reification
+
+ import definitions._
+
+ object TypedOrAnnotated {
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ case ty @ Typed(_, _) =>
+ Some(ty)
+ case at @ Annotated(_, _) =>
+ Some(at)
+ case _ =>
+ None
+ }
+ }
+
+ object TreeSplice {
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ case Select(splicee, _) if tree.symbol == ExprEval || tree.symbol == ExprValue =>
+ Some(splicee)
+ case _ =>
+ None
+ }
+ }
+
+ object EvalSplice {
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ case Select(splicee, _) if tree.symbol == ExprEval =>
+ Some(splicee)
+ case _ =>
+ None
+ }
+ }
+
+ object ValueSplice {
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ case Select(splicee, _) if tree.symbol == ExprValue =>
+ Some(splicee)
+ case _ =>
+ None
+ }
+ }
+
+ object Reified {
+ def unapply(tree: Tree): Option[(Tree, List[ValDef], Tree)] = tree match {
+ case ReifiedTree(reifee, symbolTable, reified, _) =>
+ Some(reifee, symbolTable, reified)
+ case ReifiedType(reifee, symbolTable, reified) =>
+ Some(reifee, symbolTable, reified)
+ case _ =>
+ None
+ }
+ }
+
+ object ReifiedTree {
+ def unapply(tree: Tree): Option[(Tree, List[ValDef], Tree, Tree)] = tree match {
+ case reifee @ Block((mrDef @ ValDef(_, _, _, _)) :: symbolTable, Apply(Apply(_, List(tree)), List(Apply(_, List(tpe))))) if mrDef.name == nme.MIRROR_SHORT =>
+ Some(reifee, symbolTable map (_.asInstanceOf[ValDef]), tree, tpe)
+ case _ =>
+ None
+ }
+ }
+
+ object InlineableTreeSplice {
+ def unapply(tree: Tree): Option[(Tree, List[ValDef], Tree, Tree, Symbol)] = tree match {
+ case select @ Select(ReifiedTree(splicee, symbolTable, tree, tpe), _) if select.symbol == ExprEval || select.symbol == ExprValue =>
+ Some(splicee, symbolTable, tree, tpe, select.symbol)
+ case _ =>
+ None
+ }
+ }
+
+ object InlinedTreeSplice {
+ def unapply(tree: Tree): Option[(Tree, List[ValDef], Tree, Tree)] = tree match {
+ case Select(ReifiedTree(splicee, symbolTable, tree, tpe), name) if name == ExprTree.name =>
+ Some(splicee, symbolTable, tree, tpe)
+ case _ =>
+ None
+ }
+ }
+
+ object ReifiedType {
+ def unapply(tree: Tree): Option[(Tree, List[ValDef], Tree)] = tree match {
+ case reifee @ Block((mrDef @ ValDef(_, _, _, _)) :: symbolTable, Apply(_, List(tpe))) if mrDef.name == nme.MIRROR_SHORT =>
+ Some(reifee, symbolTable map (_.asInstanceOf[ValDef]), tpe)
+ case _ =>
+ None
+ }
+ }
+
+ object InlinedTypeSplice {
+ def unapply(tree: Tree): Option[(Tree, List[ValDef], Tree)] = tree match {
+ case Select(ReifiedType(splicee, symbolTable, tpe), name) if name == TypeTagTpe.name =>
+ Some(splicee, symbolTable, tpe)
+ case _ =>
+ None
+ }
+ }
+
+ object FreeDef {
+ def unapply(tree: Tree): Option[(Tree, TermName, Tree, String)] = tree match {
+ case FreeTermDef(mrRef, name, binding, origin) =>
+ Some(mrRef, name, binding, origin)
+ case FreeTypeDef(mrRef, name, binding, origin) =>
+ Some(mrRef, name, binding, origin)
+ case _ =>
+ None
+ }
+ }
+
+ object FreeTermDef {
+ lazy val newFreeTermMethod = getMember(getRequiredClass("scala.reflect.api.TreeBuildUtil"), nme.newFreeTerm)
+
+ def unapply(tree: Tree): Option[(Tree, TermName, Tree, String)] = tree match {
+ case ValDef(_, name, _, Apply(Select(mrRef @ Ident(_), newFreeTerm), List(_, _, binding, Literal(Constant(origin: String)))))
+ if mrRef.name == nme.MIRROR_SHORT && newFreeTerm == newFreeTermMethod.name =>
+ Some(mrRef, name, binding, origin)
+ case _ =>
+ None
+ }
+ }
+
+ object FreeTypeDef {
+ lazy val newFreeTypeMethod = getMember(getRequiredClass("scala.reflect.api.TreeBuildUtil"), nme.newFreeType)
+
+ def unapply(tree: Tree): Option[(Tree, TermName, Tree, String)] = tree match {
+ case ValDef(_, name, _, Apply(Select(mrRef1 @ Ident(_), newFreeType), List(_, _, value, Literal(Constant(origin: String)))))
+ if mrRef1.name == nme.MIRROR_SHORT && newFreeType == newFreeTypeMethod.name =>
+ value match {
+ case Apply(TypeApply(Select(Select(mrRef2 @ Ident(_), typeTag), apply), List(binding)), List(Literal(Constant(null))))
+ if mrRef2.name == nme.MIRROR_SHORT && typeTag == nme.TypeTag && apply == nme.apply =>
+ Some(mrRef1, name, binding, origin)
+ case Apply(TypeApply(Select(mrRef2 @ Ident(_), typeTag), List(binding)), List(Literal(Constant(null))))
+ if mrRef2.name == nme.MIRROR_SHORT && typeTag == nme.TypeTag =>
+ Some(mrRef1, name, binding, origin)
+ case _ =>
+ throw new Error("unsupported free type def: " + showRaw(tree))
+ }
+ case _ =>
+ None
+ }
+ }
+
+ object FreeRef {
+ def unapply(tree: Tree): Option[(Tree, TermName)] = tree match {
+ case Apply(Select(mrRef @ Ident(_), ident), List(Ident(name: TermName))) if ident == nme.Ident && name.startsWith(nme.MIRROR_FREE_PREFIX) =>
+ Some(mrRef, name)
+ case _ =>
+ None
+ }
+ }
+
+ object TypeRefToFreeType {
+ def unapply(tree: Tree): Option[TermName] = tree match {
+ case Apply(Select(Select(mrRef @ Ident(_), typeRef), apply), List(Select(_, noSymbol), Ident(freeType: TermName), nil))
+ if (mrRef.name == nme.MIRROR_SHORT && typeRef == nme.TypeRef && noSymbol == nme.NoSymbol && freeType.startsWith(nme.MIRROR_FREE_PREFIX)) =>
+ Some(freeType)
+ case _ =>
+ None
+ }
+ }
+
+ object NestedExpr {
+ def unapply(tree: Tree): Option[(Tree, Tree, Tree)] = tree match {
+ case Apply(Apply(factory @ Select(expr, apply), List(tree)), List(typetag)) if expr.symbol == ExprModule && apply == nme.apply =>
+ Some(factory, tree, typetag)
+ case _ =>
+ None
+ }
+ }
+
+ object BoundTerm {
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ case Ident(name) if name.isTermName =>
+ Some(tree)
+ case This(_) =>
+ Some(tree)
+ case _ =>
+ None
+ }
+ }
+
+ object BoundType {
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ case Select(_, name) if name.isTypeName =>
+ Some(tree)
+ case SelectFromTypeTree(_, name) if name.isTypeName =>
+ Some(tree)
+ case Ident(name) if name.isTypeName =>
+ Some(tree)
+ case _ =>
+ None
+ }
+ }
}
diff --git a/src/compiler/scala/reflect/internal/TreePrinters.scala b/src/compiler/scala/reflect/internal/TreePrinters.scala
index 8ed0ee6357..9b4c18ce86 100644
--- a/src/compiler/scala/reflect/internal/TreePrinters.scala
+++ b/src/compiler/scala/reflect/internal/TreePrinters.scala
@@ -23,6 +23,7 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable =>
else s
}
def quotedName(name: Name): String = quotedName(name, false)
+ def quotedName(name: String): String = quotedName(newTermName(name), false)
private def symNameInternal(tree: Tree, name: Name, decoded: Boolean): String = {
val sym = tree.symbol
@@ -31,7 +32,7 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable =>
var suffix = ""
if (settings.uniqid.value) suffix += ("#" + sym.id)
if (settings.Yshowsymkinds.value) suffix += ("#" + sym.abbreviatedKindString)
- prefix + tree.symbol.decodedName + suffix
+ prefix + quotedName(tree.symbol.decodedName) + suffix
} else {
quotedName(name, decoded)
}
@@ -64,7 +65,7 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable =>
def indent() = indentMargin += indentStep
def undent() = indentMargin -= indentStep
- def printPosition(tree: Tree) = if (doPrintPositions) print(showPos(tree.pos))
+ def printPosition(tree: Tree) = if (doPrintPositions) print(tree.pos.show)
def println() {
out.println()
@@ -175,7 +176,7 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable =>
printAnnotations(tree)
printModifiers(tree, mods)
val word =
- if (mods.hasTraitFlag) "trait"
+ if (mods.isTrait) "trait"
else if (ifSym(tree, _.isModuleClass)) "object"
else "class"
diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala
index 1a40e0105c..0d7e68aee3 100644
--- a/src/compiler/scala/reflect/internal/Trees.scala
+++ b/src/compiler/scala/reflect/internal/Trees.scala
@@ -42,7 +42,6 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
/* Abstract types from HasFlags. */
- type FlagsType = Long
type AccessBoundaryType = Name
type AnnotationType = Tree
@@ -57,11 +56,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
def hasAccessBoundary = privateWithin != tpnme.EMPTY
def hasAllFlags(mask: Long): Boolean = (flags & mask) == mask
def hasFlag(flag: Long) = (flag & flags) != 0L
- def hasFlagsToString(mask: Long): String = flagsToString(
- flags & mask,
- if (hasAccessBoundary) privateWithin.toString else ""
- )
- def defaultFlagString = hasFlagsToString(-1L)
+
def & (flag: Long): Modifiers = {
val flags1 = flags & flag
if (flags1 == flags) this
@@ -91,7 +86,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
override def mapAnnotations(f: List[Tree] => List[Tree]): Modifiers =
Modifiers(flags, privateWithin, f(annotations)) setPositions positions
- override def toString = "Modifiers(%s, %s, %s)".format(defaultFlagString, annotations mkString ", ", positions)
+ override def toString = "Modifiers(%s, %s, %s)".format(flagString, annotations mkString ", ", positions)
}
def Modifiers(flags: Long, privateWithin: Name): Modifiers = Modifiers(flags, privateWithin, List())
@@ -189,7 +184,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
def ValDef(sym: Symbol, rhs: Tree): ValDef =
atPos(sym.pos) {
ValDef(Modifiers(sym.flags), sym.name.toTermName,
- TypeTree(sym.tpe) setPos focusPos(sym.pos),
+ TypeTree(sym.tpe) setPos sym.pos.focus,
rhs) setSymbol sym
}
@@ -208,7 +203,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
sym.name.toTermName,
sym.typeParams map TypeDef,
vparamss,
- TypeTree(sym.tpe.finalResultType) setPos focusPos(sym.pos),
+ TypeTree(sym.tpe.finalResultType) setPos sym.pos.focus,
rhs) setSymbol sym
}
@@ -240,7 +235,8 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
/** casedef shorthand */
- def CaseDef(pat: Tree, body: Tree): CaseDef = CaseDef(pat, EmptyTree, body)
+ def CaseDef(pat: Tree, body: Tree): CaseDef =
+ CaseDef(pat, EmptyTree, body)
def Bind(sym: Symbol, body: Tree): Bind =
Bind(sym.name, body) setSymbol sym
@@ -254,10 +250,39 @@ trait Trees extends api.Trees { self: SymbolTable =>
def Apply(sym: Symbol, args: Tree*): Tree =
Apply(Ident(sym), args.toList)
+ /** Factory method for object creation `new tpt(args_1)...(args_n)`
+ * A `New(t, as)` is expanded to: `(new t).<init>(as)`
+ */
+ def New(tpt: Tree, argss: List[List[Tree]]): Tree = argss match {
+ case Nil => new ApplyConstructor(tpt, Nil)
+ case xs :: rest => rest.foldLeft(new ApplyConstructor(tpt, xs): Tree)(Apply)
+ }
+
+ /** 0-1 argument list new, based on a type.
+ */
+ def New(tpe: Type, args: Tree*): Tree =
+ new ApplyConstructor(TypeTree(tpe), args.toList)
+
def New(sym: Symbol, args: Tree*): Tree =
New(sym.tpe, args: _*)
- def Super(sym: Symbol, mix: TypeName): Tree = Super(This(sym), mix)
+ def Super(sym: Symbol, mix: TypeName): Tree =
+ Super(This(sym), mix)
+
+ def This(sym: Symbol): Tree =
+ This(sym.name.toTypeName) setSymbol sym
+
+ def Select(qualifier: Tree, name: String): Select =
+ Select(qualifier, newTermName(name))
+
+ def Select(qualifier: Tree, sym: Symbol): Select =
+ Select(qualifier, sym.name) setSymbol sym
+
+ def Ident(name: String): Ident =
+ Ident(newTermName(name))
+
+ def Ident(sym: Symbol): Ident =
+ Ident(sym.name) setSymbol sym
/** Block factory that flattens directly nested blocks.
*/
@@ -271,6 +296,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
// --- specific traversers and transformers
+ // todo. move these into scala.reflect.api
protected[scala] def duplicateTree(tree: Tree): Tree = duplicator transform tree
@@ -278,44 +304,11 @@ trait Trees extends api.Trees { self: SymbolTable =>
override val treeCopy = newStrictTreeCopier
override def transform(t: Tree) = {
val t1 = super.transform(t)
- if ((t1 ne t) && isRangePos(t1.pos)) t1 setPos focusPos(t.pos)
+ if ((t1 ne t) && t1.pos.isRange) t1 setPos t.pos.focus
t1
}
}
- trait PosAssigner extends Traverser {
- var pos: Position
- }
- protected[this] lazy val posAssigner: PosAssigner = new DefaultPosAssigner
-
- protected class DefaultPosAssigner extends PosAssigner {
- var pos: Position = _
- override def traverse(t: Tree) {
- if (t eq EmptyTree) ()
- else if (t.pos == NoPosition) {
- t.setPos(pos)
- super.traverse(t) // TODO: bug? shouldn't the traverse be outside of the if?
- // @PP: it's pruning whenever it encounters a node with a
- // position, which I interpret to mean that (in the author's
- // mind at least) either the children of a positioned node will
- // already be positioned, or the children of a positioned node
- // do not merit positioning.
- //
- // Whatever the author's rationale, it does seem like a bad idea
- // to press on through a positioned node to find unpositioned
- // children beneath it and then to assign whatever happens to
- // be in `pos` to such nodes. There are supposed to be some
- // position invariants which I can't imagine surviving that.
- }
- }
- }
-
- def atPos[T <: Tree](pos: Position)(tree: T): T = {
- posAssigner.pos = pos
- posAssigner.traverse(tree)
- tree
- }
-
class ForeachPartialTreeTraverser(pf: PartialFunction[Tree, Tree]) extends Traverser {
override def traverse(tree: Tree) {
val t = if (pf isDefinedAt tree) pf(tree) else tree
@@ -368,7 +361,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
override def toString = substituterString("Symbol", "Tree", from, to)
}
- /** Substitute clazz.this with `to`. `to` must be an attributed tree.
+ /** Substitute clazz.this with `to`. `to` must be an attributed tree.
*/
class ThisSubstituter(clazz: Symbol, to: => Tree) extends Transformer {
val newtpe = to.tpe
@@ -435,4 +428,3 @@ trait Trees extends api.Trees { self: SymbolTable =>
override def toString() = "TreeSymSubstituter/" + substituterString("Symbol", "Symbol", from, to)
}
}
-
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index 46c56ccd4c..797b5db127 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -254,7 +254,9 @@ trait Types extends api.Types { self: SymbolTable =>
case object UnmappableTree extends TermTree {
override def toString = "<unmappable>"
super.tpe_=(NoType)
- override def tpe_=(t: Type) = if (t != NoType) throw new UnsupportedOperationException("tpe_=("+t+") inapplicable for <empty>")
+ override def tpe_=(t: Type) = if (t != NoType) {
+ throw new UnsupportedOperationException("tpe_=("+t+") inapplicable for <empty>")
+ }
}
abstract class AbsTypeImpl extends AbsType { this: Type =>
@@ -262,7 +264,7 @@ trait Types extends api.Types { self: SymbolTable =>
def nonPrivateDeclaration(name: Name): Symbol = nonPrivateDecl(name)
def declarations = decls
def typeArguments = typeArgs
- def erasedType = transformedType(this)
+ def erasure = transformedType(this)
def substituteTypes(from: List[Symbol], to: List[Type]): Type = subst(from, to)
}
@@ -723,6 +725,9 @@ trait Types extends api.Types { self: SymbolTable =>
/** Apply `f` to each part of this type */
def foreach(f: Type => Unit) { new ForEachTypeTraverser(f).traverse(this) }
+ /** Apply `pf' to each part of this type on which the function is defined */
+ def collect[T](pf: PartialFunction[Type, T]): List[T] = new CollectTypeCollector(pf).collect(this)
+
/** Apply `f` to each part of this type; children get mapped before their parents */
def map(f: Type => Type): Type = new TypeMap {
def apply(x: Type) = f(mapOver(x))
@@ -1194,6 +1199,8 @@ trait Types extends api.Types { self: SymbolTable =>
override def kind = "BoundedWildcardType"
}
+ object BoundedWildcardType extends BoundedWildcardTypeExtractor
+
/** An object representing a non-existing type */
case object NoType extends Type {
override def isTrivial: Boolean = true
@@ -1822,7 +1829,35 @@ trait Types extends api.Types { self: SymbolTable =>
object ConstantType extends ConstantTypeExtractor {
def apply(value: Constant): ConstantType = {
- unique(new UniqueConstantType(value)).asInstanceOf[ConstantType]
+ val tpe = new UniqueConstantType(value)
+ if (value.tag == ClazzTag) {
+ // if we carry a classOf, we might be in trouble
+ // http://groups.google.com/group/scala-internals/browse_thread/thread/45185b341aeb6a30
+ // I don't have time for a thorough fix, so I put a hacky workaround here
+ val alreadyThere = uniques findEntry tpe
+ if ((alreadyThere ne null) && (alreadyThere ne tpe) && (alreadyThere.toString != tpe.toString)) {
+ // we need to remove a stale type that has the same hashcode as we do
+ // HashSet doesn't support removal, and this makes our task non-trivial
+ // also we cannot simply recreate it, because that'd skew hashcodes (that change over time, omg!)
+ // the only solution I can see is getting into the underlying array and sneakily manipulating it
+ val ftable = uniques.getClass.getDeclaredFields().find(f => f.getName endsWith "table").get
+ ftable.setAccessible(true)
+ val table = ftable.get(uniques).asInstanceOf[Array[AnyRef]]
+ def overwrite(hc: Int, x: Type) {
+ def index(x: Int): Int = math.abs(x % table.length)
+ var h = index(hc)
+ var entry = table(h)
+ while (entry ne null) {
+ if (x == entry)
+ table(h) = x
+ h = index(h + 1)
+ entry = table(h)
+ }
+ }
+ overwrite(tpe.##, tpe)
+ }
+ }
+ unique(tpe).asInstanceOf[ConstantType]
}
}
@@ -3339,6 +3374,10 @@ trait Types extends api.Types { self: SymbolTable =>
case _ => abort(debugString(tycon))
}
+ /** Very convenient. */
+ def appliedType(tyconSym: Symbol, args: Type*): Type =
+ appliedType(tyconSym.typeConstructor, args.toList)
+
/** A creator for existential types where the type arguments,
* rather than being applied directly, are interpreted as the
* upper bounds of unknown types. For instance if the type argument
@@ -3754,6 +3793,8 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
+ // todo. move these into scala.reflect.api
+
/** A prototype for mapping a function over all possible types
*/
abstract class TypeMap extends (Type => Type) {
@@ -4566,6 +4607,16 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
+ /** 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)
@@ -6562,6 +6613,16 @@ trait Types extends api.Types { self: SymbolTable =>
try { explainSwitch = true; op } finally { explainSwitch = s }
}
+ def isUnboundedGeneric(tp: Type) = tp match {
+ case t @ TypeRef(_, sym, _) => sym.isAbstractType && !(t <:< AnyRefClass.tpe)
+ case _ => false
+ }
+ def isBoundedGeneric(tp: Type) = tp match {
+ case TypeRef(_, sym, _) if sym.isAbstractType => (tp <:< AnyRefClass.tpe)
+ case TypeRef(_, sym, _) => !isPrimitiveValueClass(sym)
+ case _ => false
+ }
+
def objToAny(tp: Type): Type =
if (!phase.erasedTypes && tp.typeSymbol == ObjectClass) AnyClass.tpe
else tp
diff --git a/src/compiler/scala/reflect/internal/pickling/UnPickler.scala b/src/compiler/scala/reflect/internal/pickling/UnPickler.scala
index f1ec64bda9..f89aa9bf5c 100644
--- a/src/compiler/scala/reflect/internal/pickling/UnPickler.scala
+++ b/src/compiler/scala/reflect/internal/pickling/UnPickler.scala
@@ -257,12 +257,11 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ {
}
def isModuleFlag = (flags & MODULE) != 0L
- def isMethodFlag = (flags & METHOD) != 0L
def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner)
def isModuleRoot = (name == moduleRoot.name) && (owner == moduleRoot.owner)
+ def pflags = flags & PickledFlags
def finishSym(sym: Symbol): Symbol = {
- sym.flags = flags & PickledFlags
sym.privateWithin = privateWithin
sym.info = (
if (atEnd) {
@@ -282,27 +281,27 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ {
}
finishSym(tag match {
- case TYPEsym => owner.newAbstractType(name.toTypeName)
- case ALIASsym => owner.newAliasType(name.toTypeName)
+ case TYPEsym | ALIASsym =>
+ owner.newNonClassSymbol(name.toTypeName, NoPosition, pflags)
case CLASSsym =>
- val sym = (isClassRoot, isModuleFlag) match {
- case (true, true) => moduleRoot.moduleClass
- case (true, false) => classRoot
- case (false, true) => owner.newModuleClass(name.toTypeName)
- case (false, false) => owner.newClass(name.toTypeName)
- }
+ val sym = (
+ if (isClassRoot) {
+ if (isModuleFlag) moduleRoot.moduleClass setFlag pflags
+ else classRoot setFlag pflags
+ }
+ else owner.newClassSymbol(name.toTypeName, NoPosition, pflags)
+ )
if (!atEnd)
sym.typeOfThis = newLazyTypeRef(readNat())
sym
case MODULEsym =>
val clazz = at(inforef, () => readType()).typeSymbol // after the NMT_TRANSITION period, we can leave off the () => ... ()
- if (isModuleRoot) moduleRoot
- else owner.newLinkedModule(clazz)
+ if (isModuleRoot) moduleRoot setFlag pflags
+ else owner.newLinkedModule(clazz, pflags)
case VALsym =>
if (isModuleRoot) { assert(false); NoSymbol }
- else if (isMethodFlag) owner.newMethod(name.toTermName)
- else owner.newValue(name.toTermName)
+ else owner.newTermSymbol(name.toTermName, NoPosition, pflags)
case _ =>
errorBadSignature("bad symbol tag: " + tag)
diff --git a/src/compiler/scala/reflect/internal/transform/Erasure.scala b/src/compiler/scala/reflect/internal/transform/Erasure.scala
index e87de8db80..1b323f839b 100644
--- a/src/compiler/scala/reflect/internal/transform/Erasure.scala
+++ b/src/compiler/scala/reflect/internal/transform/Erasure.scala
@@ -69,6 +69,9 @@ trait Erasure {
clazz.firstParamAccessor.tpe.resultType
abstract class ErasureMap extends TypeMap {
+ private lazy val ObjectArray = arrayType(ObjectClass.tpe)
+ private lazy val ErasedObject = erasedTypeRef(ObjectClass)
+
def mergeParents(parents: List[Type]): Type
def eraseNormalClassRef(pre: Type, clazz: Symbol): Type =
@@ -87,7 +90,7 @@ trait Erasure {
if (unboundedGenericArrayLevel(tp) == 1) ObjectClass.tpe
else if (args.head.typeSymbol.isBottomClass) ObjectArray
else typeRef(apply(pre), sym, args map applyInArray)
- else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass || sym == NotNullClass) erasedTypeRef(ObjectClass)
+ else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass || sym == NotNullClass) ErasedObject
else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass)
else if (sym.isRefinementClass) apply(mergeParents(tp.parents))
else if (sym.isDerivedValueClass) eraseDerivedValueClassRef(sym)
@@ -111,7 +114,7 @@ trait Erasure {
case ClassInfoType(parents, decls, clazz) =>
ClassInfoType(
if (clazz == ObjectClass || isPrimitiveValueClass(clazz)) Nil
- else if (clazz == ArrayClass) List(erasedTypeRef(ObjectClass))
+ else if (clazz == ArrayClass) List(ErasedObject)
else removeLaterObjects(parents map this),
decls, clazz)
case _ =>
diff --git a/src/compiler/scala/reflect/internal/transform/UnCurry.scala b/src/compiler/scala/reflect/internal/transform/UnCurry.scala
index fd6d4e177d..0c1640ceb9 100644
--- a/src/compiler/scala/reflect/internal/transform/UnCurry.scala
+++ b/src/compiler/scala/reflect/internal/transform/UnCurry.scala
@@ -12,14 +12,8 @@ trait UnCurry {
private def expandAlias(tp: Type): Type = if (!tp.isHigherKinded) tp.normalize else tp
- private def isUnboundedGeneric(tp: Type) = tp match {
- case t @ TypeRef(_, sym, _) => sym.isAbstractType && !(t <:< AnyRefClass.tpe)
- case _ => false
- }
-
val uncurry: TypeMap = new TypeMap {
def apply(tp0: Type): Type = {
- // tp0.typeSymbolDirect.initialize
val tp = expandAlias(tp0)
tp match {
case MethodType(params, MethodType(params1, restpe)) =>
@@ -31,13 +25,13 @@ trait UnCurry {
apply(MethodType(h.cloneSymbol.resetFlag(IMPLICIT) :: t, restpe))
case NullaryMethodType(restpe) =>
apply(MethodType(List(), restpe))
- case TypeRef(pre, ByNameParamClass, List(arg)) =>
+ case TypeRef(pre, ByNameParamClass, arg :: Nil) =>
apply(functionType(List(), arg))
- case TypeRef(pre, RepeatedParamClass, args) =>
- apply(appliedType(SeqClass.typeConstructor, args))
- case TypeRef(pre, JavaRepeatedParamClass, args) =>
+ case TypeRef(pre, RepeatedParamClass, arg :: Nil) =>
+ apply(seqType(arg))
+ case TypeRef(pre, JavaRepeatedParamClass, arg :: Nil) =>
apply(arrayType(
- if (isUnboundedGeneric(args.head)) ObjectClass.tpe else args.head))
+ if (isUnboundedGeneric(arg)) ObjectClass.tpe else arg))
case _ =>
expandAlias(mapOver(tp))
}
diff --git a/src/compiler/scala/reflect/internal/util/Collections.scala b/src/compiler/scala/reflect/internal/util/Collections.scala
index d26a1abadb..9dbf1adeef 100644
--- a/src/compiler/scala/reflect/internal/util/Collections.scala
+++ b/src/compiler/scala/reflect/internal/util/Collections.scala
@@ -10,6 +10,8 @@ import scala.annotation.tailrec
import mutable.ListBuffer
/** Profiler driven changes.
+ * TODO - inlining doesn't work from here because of the bug that
+ * methods in traits aren't inlined.
*/
trait Collections {
/** True if all three arguments have the same number of elements and
@@ -75,7 +77,8 @@ trait Collections {
}
}
- @inline final def findOrElse[A](xs: TraversableOnce[A])(p: A => Boolean)(orElse: => A): A = {
+ // @inline
+ final def findOrElse[A](xs: TraversableOnce[A])(p: A => Boolean)(orElse: => A): A = {
xs find p getOrElse orElse
}
diff --git a/src/compiler/scala/reflect/makro/runtime/Aliases.scala b/src/compiler/scala/reflect/makro/runtime/Aliases.scala
new file mode 100644
index 0000000000..a4f208ca34
--- /dev/null
+++ b/src/compiler/scala/reflect/makro/runtime/Aliases.scala
@@ -0,0 +1,21 @@
+package scala.reflect.makro
+package runtime
+
+trait Aliases {
+ self: Context =>
+
+ /** Aliases of mirror types */
+ override type Symbol = mirror.Symbol
+ override type Type = mirror.Type
+ override type Name = mirror.Name
+ override type Tree = mirror.Tree
+ override type Position = mirror.Position
+ override type Scope = mirror.Scope
+ override type Modifiers = mirror.Modifiers
+ override type Expr[+T] = mirror.Expr[T]
+ override type TypeTag[T] = mirror.TypeTag[T]
+
+ /** Creator/extractor objects for Expr and TypeTag values */
+ override val TypeTag = mirror.TypeTag
+ override val Expr = mirror.Expr
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/makro/runtime/CapturedVariables.scala b/src/compiler/scala/reflect/makro/runtime/CapturedVariables.scala
new file mode 100644
index 0000000000..4e93d4e06d
--- /dev/null
+++ b/src/compiler/scala/reflect/makro/runtime/CapturedVariables.scala
@@ -0,0 +1,14 @@
+package scala.reflect.makro
+package runtime
+
+trait CapturedVariables {
+ self: Context =>
+
+ import mirror._
+
+ def captureVariable(vble: Symbol): Unit = mirror.captureVariable(vble)
+
+ def referenceCapturedVariable(vble: Symbol): Tree = mirror.referenceCapturedVariable(vble)
+
+ def capturedVariableType(vble: Symbol): Type = mirror.capturedVariableType(vble)
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/makro/runtime/Context.scala b/src/compiler/scala/reflect/makro/runtime/Context.scala
new file mode 100644
index 0000000000..184008658e
--- /dev/null
+++ b/src/compiler/scala/reflect/makro/runtime/Context.scala
@@ -0,0 +1,26 @@
+package scala.reflect.makro
+package runtime
+
+import scala.tools.nsc.Global
+
+abstract class Context extends scala.reflect.makro.Context
+ with Aliases
+ with CapturedVariables
+ with Infrastructure
+ with Enclosures
+ with Names
+ with Reifiers
+ with Reporters
+ with Settings
+ with Symbols
+ with Typers
+ with Util {
+
+ val mirror: Global
+
+ val callsiteTyper: mirror.analyzer.Typer
+
+ val prefix: Expr[PrefixType]
+
+ val expandee: Tree
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/makro/runtime/Enclosures.scala b/src/compiler/scala/reflect/makro/runtime/Enclosures.scala
new file mode 100644
index 0000000000..f9a6987e48
--- /dev/null
+++ b/src/compiler/scala/reflect/makro/runtime/Enclosures.scala
@@ -0,0 +1,36 @@
+package scala.reflect.makro
+package runtime
+
+trait Enclosures {
+ self: Context =>
+
+ import mirror._
+
+ // vals are eager to simplify debugging
+ // after all we wouldn't save that much time by making them lazy
+
+ val macroApplication: Tree = expandee
+
+ val enclosingMacros: List[Context] = this :: mirror.analyzer.openMacros
+
+ val enclosingImplicits: List[(Type, Tree)] = callsiteTyper.context.openImplicits
+
+ val enclosingPosition: Position = enclosingMacros.find(c => c.macroApplication.pos != NoPosition).map(_.macroApplication.pos).getOrElse(NoPosition)
+
+ val enclosingApplication: Tree = {
+ def loop(context: analyzer.Context): Tree = context match {
+ case analyzer.NoContext => EmptyTree
+ case context if context.tree.isInstanceOf[Apply] => context.tree
+ case context => loop(context.outer)
+ }
+
+ val context = callsiteTyper.context
+ loop(context)
+ }
+
+ val enclosingMethod: Tree = callsiteTyper.context.enclMethod.tree
+
+ val enclosingClass: Tree = callsiteTyper.context.enclClass.tree
+
+ val enclosingUnit: CompilationUnit = currentRun.currentUnit
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/makro/runtime/Errors.scala b/src/compiler/scala/reflect/makro/runtime/Errors.scala
new file mode 100644
index 0000000000..d78eae9237
--- /dev/null
+++ b/src/compiler/scala/reflect/makro/runtime/Errors.scala
@@ -0,0 +1,6 @@
+package scala.reflect.makro
+package runtime
+
+import scala.reflect.api.Position
+
+class AbortMacroException(val pos: Position, val msg: String) extends Throwable(msg)
diff --git a/src/compiler/scala/reflect/makro/runtime/Infrastructure.scala b/src/compiler/scala/reflect/makro/runtime/Infrastructure.scala
new file mode 100644
index 0000000000..6d8e55cc35
--- /dev/null
+++ b/src/compiler/scala/reflect/makro/runtime/Infrastructure.scala
@@ -0,0 +1,34 @@
+package scala.reflect.makro
+package runtime
+
+trait Infrastructure {
+ self: Context =>
+
+ val forJVM: Boolean = mirror.forJVM
+
+ val forMSIL: Boolean = mirror.forMSIL
+
+ val forInteractive: Boolean = mirror.forInteractive
+
+ val forScaladoc: Boolean = mirror.forScaladoc
+
+ val currentRun: Run = mirror.currentRun
+
+ type Run = mirror.Run
+
+ object Run extends RunExtractor {
+ def unapply(run: Run): Option[(CompilationUnit, List[CompilationUnit])] = Some(run.currentUnit, run.units.toList)
+ }
+
+ type CompilationUnit = mirror.CompilationUnit
+
+ object CompilationUnit extends CompilationUnitExtractor {
+ def unapply(compilationUnit: CompilationUnit): Option[(java.io.File, Array[Char], Tree)] = Some(compilationUnit.source.file.file, compilationUnit.source.content, compilationUnit.body)
+ }
+
+ val currentMacro: Symbol = expandee.symbol
+
+ val globalCache: collection.mutable.Map[Any, Any] = mirror.analyzer.globalMacroCache
+
+ val cache: collection.mutable.Map[Any, Any] = mirror.analyzer.perRunMacroCache.getOrElseUpdate(currentMacro, collection.mutable.Map[Any, Any]())
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/makro/runtime/Names.scala b/src/compiler/scala/reflect/makro/runtime/Names.scala
new file mode 100644
index 0000000000..d8ecc2b89e
--- /dev/null
+++ b/src/compiler/scala/reflect/makro/runtime/Names.scala
@@ -0,0 +1,20 @@
+package scala.reflect.makro
+package runtime
+
+trait Names {
+ self: Context =>
+
+ lazy val freshNameCreator = callsiteTyper.context.unit.fresh
+
+ def fresh(): String = {
+ freshNameCreator.newName()
+ }
+
+ def fresh(name: String): String = {
+ freshNameCreator.newName(name)
+ }
+
+ def fresh(name: Name): Name = {
+ name.mapName(freshNameCreator.newName(_))
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/makro/runtime/Reifiers.scala b/src/compiler/scala/reflect/makro/runtime/Reifiers.scala
new file mode 100644
index 0000000000..2488b06d6c
--- /dev/null
+++ b/src/compiler/scala/reflect/makro/runtime/Reifiers.scala
@@ -0,0 +1,69 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Gilles Dubochet
+ */
+
+package scala.reflect.makro
+package runtime
+
+trait Reifiers {
+ self: Context =>
+
+ import mirror._
+
+ lazy val reflectMirrorPrefix: Tree = {
+ // [Eugene] how do I typecheck this without undergoing this tiresome (and, in general, incorrect) procedure?
+ val prefix: Tree = Select(Select(Ident(definitions.ScalaPackage), newTermName("reflect")), newTermName("mirror"))
+ val prefixTpe = typeCheck(TypeApply(Select(prefix, newTermName("asInstanceOf")), List(SingletonTypeTree(prefix)))).tpe
+ typeCheck(prefix) setType prefixTpe
+ }
+
+ def reifyTree(prefix: Tree, tree: Tree): Tree =
+ reifyTopLevel(prefix, tree)
+
+ def reifyType(prefix: Tree, tpe: Type, dontSpliceAtTopLevel: Boolean = false, requireConcreteTypeTag: Boolean = false): Tree =
+ reifyTopLevel(prefix, tpe, dontSpliceAtTopLevel, requireConcreteTypeTag)
+
+ def unreifyTree(tree: Tree): Tree =
+ Select(tree, definitions.ExprEval)
+
+ def reifyTopLevel(prefix: Tree, reifee: Any, dontSpliceAtTopLevel: Boolean = false, requireConcreteTypeTag: Boolean = false): Tree = {
+ // [Eugene] the plumbing is not very pretty, but anyways factoring out the reifier seems like a necessary step to me
+ import scala.reflect.reify._
+ val reifier = mkReifier(mirror)(callsiteTyper, prefix, reifee, dontSpliceAtTopLevel, requireConcreteTypeTag)
+
+ try {
+ val result = reifier.reified
+ logFreeVars(expandee.pos, result)
+ result
+ } catch {
+ case ex: reifier.ReificationError =>
+// // this is a "soft" exception - it will normally be caught by the macro
+// // consequently, we need to log the stack trace here, so that it doesn't get lost
+// if (settings.Yreifydebug.value) {
+// val message = new java.io.StringWriter()
+// ex.printStackTrace(new java.io.PrintWriter(message))
+// println(scala.compat.Platform.EOL + message)
+// }
+ val xlated = new ReificationError(ex.pos, ex.msg)
+ xlated.setStackTrace(ex.getStackTrace)
+ throw xlated
+ case ex: reifier.UnexpectedReificationError =>
+ val xlated = new UnexpectedReificationError(ex.pos, ex.msg, ex.cause)
+ xlated.setStackTrace(ex.getStackTrace)
+ throw xlated
+ }
+ }
+
+ class ReificationError(var pos: Position, val msg: String) extends Throwable(msg)
+
+ object ReificationError extends ReificationErrorExtractor {
+ def unapply(error: ReificationError): Option[(Position, String)] = Some((error.pos, error.msg))
+ }
+
+ class UnexpectedReificationError(val pos: Position, val msg: String, val cause: Throwable = null) extends Throwable(msg, cause)
+
+ object UnexpectedReificationError extends UnexpectedReificationErrorExtractor {
+ def unapply(error: UnexpectedReificationError): Option[(Position, String, Throwable)] = Some((error.pos, error.msg, error.cause))
+ }
+}
diff --git a/src/compiler/scala/reflect/makro/runtime/Reporters.scala b/src/compiler/scala/reflect/makro/runtime/Reporters.scala
new file mode 100644
index 0000000000..0fd037bdd2
--- /dev/null
+++ b/src/compiler/scala/reflect/makro/runtime/Reporters.scala
@@ -0,0 +1,44 @@
+package scala.reflect.makro
+package runtime
+
+trait Reporters {
+ self: Context =>
+
+ import mirror._
+
+ def reporter: mirror.Reporter = wrapNscReporter(mirror.reporter)
+
+ def setReporter(reporter: mirror.Reporter): this.type = {
+ mirror.reporter = wrapApiReporter(reporter)
+ this
+ }
+
+ def withReporter[T](reporter: Reporter)(op: => T): T = {
+ val old = mirror.reporter
+ setReporter(reporter)
+ try op
+ finally mirror.reporter = old
+ }
+
+ def echo(pos: Position, msg: String): Unit = mirror.reporter.echo(pos, msg)
+
+ def info(pos: Position, msg: String, force: Boolean): Unit = mirror.reporter.info(pos, msg, force)
+
+ def hasWarnings: Boolean = mirror.reporter.hasErrors
+
+ def hasErrors: Boolean = mirror.reporter.hasErrors
+
+ def warning(pos: Position, msg: String): Unit = callsiteTyper.context.warning(pos, msg)
+
+ def error(pos: Position, msg: String): Unit = callsiteTyper.context.error(pos, msg)
+
+ def abort(pos: Position, msg: String): Nothing = {
+ callsiteTyper.context.error(pos, msg)
+ throw new AbortMacroException(pos, msg)
+ }
+
+ def interactive(): Unit = mirror.reporter match {
+ case reporter: tools.nsc.reporters.AbstractReporter => reporter.displayPrompt()
+ case _ => ()
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/makro/runtime/Settings.scala b/src/compiler/scala/reflect/makro/runtime/Settings.scala
new file mode 100644
index 0000000000..32f7115db8
--- /dev/null
+++ b/src/compiler/scala/reflect/makro/runtime/Settings.scala
@@ -0,0 +1,36 @@
+package scala.reflect.makro
+package runtime
+
+trait Settings {
+ self: Context =>
+
+ def settings: List[String] = {
+ val optionName = mirror.settings.XmacroSettings.name
+ val settings = compilerSettings.find(opt => opt.startsWith(optionName)).map(opt => opt.substring(optionName.length + 1)).getOrElse("")
+ settings.split(",").toList
+ }
+
+ def compilerSettings: List[String] = mirror.settings.recreateArgs
+
+ def setCompilerSettings(options: String): this.type =
+ // todo. is not going to work with quoted arguments with embedded whitespaces
+ setCompilerSettings(options.split(" ").toList)
+
+ def setCompilerSettings(options: List[String]): this.type = {
+ val settings = new tools.nsc.Settings(_ => ())
+ // [Eugene] what settings should we exclude?
+ settings.copyInto(mirror.settings)
+ this
+ }
+
+ def withCompilerSettings[T](options: String)(op: => T): T =
+ // todo. is not going to work with quoted arguments with embedded whitespaces
+ withCompilerSettings(options.split(" ").toList)(op)
+
+ def withCompilerSettings[T](options: List[String])(op: => T): T = {
+ val old = options
+ setCompilerSettings(options)
+ try op
+ finally setCompilerSettings(old)
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/makro/runtime/Symbols.scala b/src/compiler/scala/reflect/makro/runtime/Symbols.scala
new file mode 100644
index 0000000000..552ad2a303
--- /dev/null
+++ b/src/compiler/scala/reflect/makro/runtime/Symbols.scala
@@ -0,0 +1,8 @@
+package scala.reflect.makro
+package runtime
+
+trait Symbols {
+ self: Context =>
+
+ def isLocatable(sym: Symbol) = sym.isLocatable
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/makro/runtime/Typers.scala b/src/compiler/scala/reflect/makro/runtime/Typers.scala
new file mode 100644
index 0000000000..38e819746d
--- /dev/null
+++ b/src/compiler/scala/reflect/makro/runtime/Typers.scala
@@ -0,0 +1,78 @@
+package scala.reflect.makro
+package runtime
+
+trait Typers {
+ self: Context =>
+
+ val openMacros: List[Context] = this :: mirror.analyzer.openMacros
+
+ val openImplicits: List[(Type, Tree)] = callsiteTyper.context.openImplicits
+
+ def typeCheck(tree: Tree, pt: Type = mirror.WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree = {
+ def trace(msg: Any) = if (mirror.settings.Ymacrodebug.value) println(msg)
+ trace("typechecking %s with expected type %s, implicit views = %s, macros = %s".format(tree, pt, !withImplicitViewsDisabled, !withMacrosDisabled))
+ val wrapper1 = if (!withImplicitViewsDisabled) (callsiteTyper.context.withImplicitsEnabled[Tree] _) else (callsiteTyper.context.withImplicitsDisabled[Tree] _)
+ val wrapper2 = if (!withMacrosDisabled) (callsiteTyper.context.withMacrosEnabled[Tree] _) else (callsiteTyper.context.withMacrosDisabled[Tree] _)
+ def wrapper (tree: => Tree) = wrapper1(wrapper2(tree))
+ // if you get a "silent mode is not available past typer" here
+ // don't rush to change the typecheck not to use the silent method when the silent parameter is false
+ // typechecking uses silent anyways (e.g. in typedSelect), so you'll only waste your time
+ // I'd advise fixing the root cause: finding why the context is not set to report errors
+ // (also see reflect.runtime.ToolBoxes.typeCheckExpr for a workaround that might work for you)
+ wrapper(callsiteTyper.silent(_.typed(tree, mirror.analyzer.EXPRmode, pt)) match {
+ case mirror.analyzer.SilentResultValue(result) =>
+ trace(result)
+ result
+ case error @ mirror.analyzer.SilentTypeError(_) =>
+ trace(error.err.errMsg)
+ if (!silent) throw new mirror.TypeError(error.err.errPos, error.err.errMsg)
+ mirror.EmptyTree
+ })
+ }
+
+ def inferImplicitValue(pt: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: Position = enclosingPosition): Tree = {
+ def trace(msg: Any) = if (mirror.settings.Ymacrodebug.value) println(msg)
+ trace("inferring implicit value of type %s, macros = %s".format(pt, !withMacrosDisabled))
+ import mirror.analyzer.SearchResult
+ val wrapper1 = if (!withMacrosDisabled) (callsiteTyper.context.withMacrosEnabled[SearchResult] _) else (callsiteTyper.context.withMacrosDisabled[SearchResult] _)
+ def wrapper (inference: => SearchResult) = wrapper1(inference)
+ val context = callsiteTyper.context.makeImplicit(true)
+ wrapper(mirror.analyzer.inferImplicit(mirror.EmptyTree, pt, true, false, context, !silent, pos)) match {
+ case failure if failure.tree.isEmpty =>
+ trace("implicit search has failed. to find out the reason, turn on -Xlog-implicits")
+ if (context.hasErrors) throw new mirror.TypeError(context.errBuffer.head.errPos, context.errBuffer.head.errMsg)
+ mirror.EmptyTree
+ case success =>
+ success.tree
+ }
+ }
+
+ def inferImplicitView(tree: Tree, from: Type, to: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, reportAmbiguous: Boolean = true, pos: Position = enclosingPosition): Tree = {
+ def trace(msg: Any) = if (mirror.settings.Ymacrodebug.value) println(msg)
+ trace("inferring implicit view from %s to %s for %s, macros = %s, reportAmbiguous = %s".format(from, to, tree, !withMacrosDisabled, reportAmbiguous))
+ import mirror.analyzer.SearchResult
+ val wrapper1 = if (!withMacrosDisabled) (callsiteTyper.context.withMacrosEnabled[SearchResult] _) else (callsiteTyper.context.withMacrosDisabled[SearchResult] _)
+ def wrapper (inference: => SearchResult) = wrapper1(inference)
+ val fun1 = mirror.definitions.FunctionClass(1)
+ val viewTpe = mirror.TypeRef(fun1.typeConstructor.prefix, fun1, List(from, to))
+ val context = callsiteTyper.context.makeImplicit(reportAmbiguous)
+ wrapper(mirror.analyzer.inferImplicit(mirror.EmptyTree, viewTpe, reportAmbiguous, true, context, !silent, pos)) match {
+ case failure if failure.tree.isEmpty =>
+ trace("implicit search has failed. to find out the reason, turn on -Xlog-implicits")
+ if (context.hasErrors) throw new mirror.TypeError(context.errBuffer.head.errPos, context.errBuffer.head.errMsg)
+ mirror.EmptyTree
+ case success =>
+ success.tree
+ }
+ }
+
+ type TypeError = mirror.TypeError
+
+ object TypeError extends TypeErrorExtractor {
+ def unapply(error: TypeError): Option[(Position, String)] = Some((error.pos, error.msg))
+ }
+
+ def resetAllAttrs[T <: Tree](tree: T): T = mirror.resetAllAttrs(tree)
+
+ def resetLocalAttrs[T <: Tree](tree: T): T = mirror.resetLocalAttrs(tree)
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/makro/runtime/Util.scala b/src/compiler/scala/reflect/makro/runtime/Util.scala
new file mode 100644
index 0000000000..2671155721
--- /dev/null
+++ b/src/compiler/scala/reflect/makro/runtime/Util.scala
@@ -0,0 +1,34 @@
+package scala.reflect.makro
+package runtime
+
+trait Util {
+ self: Context =>
+
+ import mirror._
+
+ def literalNull = Expr[Null](Literal(Constant(null)))(TypeTag.Null)
+
+ def literalUnit = Expr[Unit](Literal(Constant(())))(TypeTag.Unit)
+
+ def literalTrue = Expr[Boolean](Literal(Constant(true)))(TypeTag.Boolean)
+
+ def literalFalse = Expr[Boolean](Literal(Constant(false)))(TypeTag.Boolean)
+
+ def literal(x: Boolean) = Expr[Boolean](Literal(Constant(x)))(TypeTag.Boolean)
+
+ def literal(x: Byte) = Expr[Byte](Literal(Constant(x)))(TypeTag.Byte)
+
+ def literal(x: Short) = Expr[Short](Literal(Constant(x)))(TypeTag.Short)
+
+ def literal(x: Int) = Expr[Int](Literal(Constant(x)))(TypeTag.Int)
+
+ def literal(x: Long) = Expr[Long](Literal(Constant(x)))(TypeTag.Long)
+
+ def literal(x: Float) = Expr[Float](Literal(Constant(x)))(TypeTag.Float)
+
+ def literal(x: Double) = Expr[Double](Literal(Constant(x)))(TypeTag.Double)
+
+ def literal(x: String) = Expr[String](Literal(Constant(x)))(TypeTag.String)
+
+ def literal(x: Char) = Expr[Char](Literal(Constant(x)))(TypeTag.Char)
+}
diff --git a/src/compiler/scala/reflect/reify/Errors.scala b/src/compiler/scala/reflect/reify/Errors.scala
new file mode 100644
index 0000000000..30c6c06c7b
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/Errors.scala
@@ -0,0 +1,63 @@
+package scala.reflect
+package reify
+
+import scala.tools.nsc.Global
+
+trait Errors {
+ self: Reifier =>
+
+ import mirror._
+ import definitions._
+
+ class ReificationError(var pos: Position, val msg: String) extends Throwable(msg)
+ class UnexpectedReificationError(val pos: Position, val msg: String, val cause: Throwable = null) extends Throwable(msg)
+
+ lazy val defaultErrorPosition: Position =
+ mirror.analyzer.openMacros.find(c => c.macroApplication.pos != NoPosition).map(_.macroApplication.pos).getOrElse(NoPosition)
+
+ // expected errors: these can happen if the user casually writes whatever.reify(...)
+ // hence we don't crash here, but nicely report a typechecking error and bail out asap
+
+ def CannotReifyReifeeThatHasTypeLocalToReifee(tree: Tree) = {
+ val msg = "implementation restriction: cannot reify block of type %s that involves a type declared inside the block being reified. consider casting the return value to a suitable type".format(tree.tpe)
+ throw new ReificationError(tree.pos, msg)
+ }
+
+ def CannotReifyType(tpe: Type) = {
+ val msg = "implementation restriction: cannot reify type %s (%s)".format(tpe, tpe.kind)
+ throw new ReificationError(defaultErrorPosition, msg)
+ }
+
+ def CannotReifySymbol(sym: Symbol) = {
+ val msg = "implementation restriction: cannot reify symbol %s (%s)".format(sym, sym.accurateKindString)
+ throw new ReificationError(defaultErrorPosition, msg)
+ }
+
+ def CannotReifyConcreteTypeTagHavingUnresolvedTypeParameters(tpe: Type) = {
+ val msg = "cannot reify ConcreteTypeTag having unresolved type parameter %s".format(tpe)
+ throw new ReificationError(defaultErrorPosition, msg)
+ }
+
+ // unexpected errors: these can never happen under normal conditions unless there's a bug in the compiler (or in a compiler plugin or in a macro)
+ // hence, we fail fast and loudly and don't care about being nice - in this situation noone will appreciate our quiet nicety
+
+ def CannotReifyUntypedPrefix(prefix: Tree) = {
+ val msg = "internal error: untyped prefixes are not supported, consider typechecking the prefix before passing it to the reifier"
+ throw new UnexpectedReificationError(defaultErrorPosition, msg)
+ }
+
+ def CannotReifyUntypedReifee(reifee: Any) = {
+ val msg = "internal error: untyped trees are not supported, consider typechecking the reifee before passing it to the reifier"
+ throw new UnexpectedReificationError(defaultErrorPosition, msg)
+ }
+
+ def CannotReifyErroneousPrefix(prefix: Tree) = {
+ val msg = "internal error: erroneous prefixes are not supported, make sure that your prefix has typechecked successfully before passing it to the reifier"
+ throw new UnexpectedReificationError(defaultErrorPosition, msg)
+ }
+
+ def CannotReifyErroneousReifee(reifee: Any) = {
+ val msg = "internal error: erroneous reifees are not supported, make sure that your reifee has typechecked successfully before passing it to the reifier"
+ throw new UnexpectedReificationError(defaultErrorPosition, msg)
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/NodePrinters.scala b/src/compiler/scala/reflect/reify/NodePrinters.scala
new file mode 100644
index 0000000000..eaca9a4968
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/NodePrinters.scala
@@ -0,0 +1,111 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package reify
+
+import scala.Array.canBuildFrom
+import scala.compat.Platform.EOL
+import scala.tools.nsc.symtab.Flags
+import scala.tools.nsc.Global
+
+trait NodePrinters { self: scala.tools.nsc.ast.NodePrinters =>
+
+ val global: Global
+ import global._
+
+ object reifiedNodeToString extends Function2[Tree, Tree, String] {
+ def apply(prefix: Tree, tree: Tree): String = {
+ import scala.reflect.api.Modifier
+ var modifierIsUsed = false
+ var flagsAreUsed = false
+
+ // @PP: I fervently hope this is a test case or something, not anything being
+ // depended upon. Of more fragile code I cannot conceive.
+ // @Eugene: This stuff is only needed to debug-print out reifications in human-readable format
+ // Rolling a full-fledged, robust TreePrinter would be several times more code.
+ val (List(mirror), reified) = (for (line <- (tree.toString.split(EOL).toList drop 1 dropRight 1)) yield {
+ var s = line.trim
+ s = s.replace("$mr.", "")
+ s = s.replace(".apply", "")
+ s = s.replace("scala.collection.immutable.", "")
+ s = "List\\[List\\[.*?\\].*?\\]".r.replaceAllIn(s, "List")
+ s = "List\\[.*?\\]".r.replaceAllIn(s, "List")
+ s = s.replace("immutable.this.Nil", "List()")
+ s = s.replace("modifiersFromInternalFlags", "Modifiers")
+ s = s.replace("Modifiers(0L, newTypeName(\"\"), List())", "Modifiers()")
+ s = """Modifiers\((\d+)[lL], newTypeName\("(.*?)"\), List\((.*?)\)\)""".r.replaceAllIn(s, m => {
+ val buf = new collection.mutable.ListBuffer[String]
+
+ val annotations = m.group(3)
+ if (buf.nonEmpty || annotations.nonEmpty)
+ buf.append("List(" + annotations + ")")
+
+ val privateWithin = "" + m.group(2)
+ if (buf.nonEmpty || privateWithin != "")
+ buf.append("newTypeName(\"" + privateWithin + "\")")
+
+ val flags = m.group(1).toLong
+ val s_flags = Flags.modifiersOfFlags(flags) map (_.sourceString) mkString ", "
+ if (buf.nonEmpty || s_flags != "") {
+ modifierIsUsed = true
+ buf.append("Set(" + s_flags + ")")
+ }
+
+ "Modifiers(" + buf.reverse.mkString(", ") + ")"
+ })
+ s = """setInternalFlags\((\d+)L\)""".r.replaceAllIn(s, m => {
+ flagsAreUsed = true
+ val flags = m.group(1).toLong
+ val mods = Flags.modifiersOfFlags(flags) map (_.sourceString)
+ "setInternalFlags(flagsOfModifiers(List(" + mods.mkString(", ") + ")))"
+ })
+
+ s
+ }) splitAt 1
+
+ val printout = collection.mutable.ListBuffer(mirror);
+ printout += "import " + nme.MIRROR_SHORT + "._"
+ if (modifierIsUsed) printout += "import scala.reflect.api.Modifier._"
+ if (flagsAreUsed) printout += "import scala.reflect.internal.Flags._"
+ val body = reified dropWhile (_.startsWith("val"))
+ if (body.length > 0 && body(0).startsWith("Expr[")) {
+ if (reified(0) startsWith "val") {
+ printout += "val code = {"
+ printout ++= (reified map (" " + _))
+ printout += "}"
+ printout += "mkToolBox().runExpr(code)"
+ } else {
+ printout += "val code = " + reified(0)
+ printout ++= reified drop 1
+ printout += "mkToolBox().runExpr(code)"
+ }
+ try {
+ val prefix = Select(Select(Ident(definitions.ScalaPackage), newTermName("reflect")), newTermName("mirror"))
+ val tree1 = new global.Transformer {
+ override def transform(tree: Tree) = super.transform(tree match {
+ case Block(ValDef(_, mr, _, _) :: Nil, expr) if mr == nme.MIRROR_SHORT => transform(expr)
+ case Block(ValDef(_, mr, _, _) :: symbolTable, expr) if mr == nme.MIRROR_SHORT => transform(Block(symbolTable, expr))
+ case Select(Ident(mr), name) if mr == nme.MIRROR_SHORT => Select(prefix, name)
+ case tree => tree
+ })
+ }.transform(tree)
+ val stringified = mkToolBox().runExpr(tree1).toString
+ if (settings.Yreifydebug.value) printout += "*****************************"
+ printout += stringified
+ } catch {
+ case ex: Throwable =>
+// val realex = ReflectionUtils.unwrapThrowable(ex)
+// val message = new java.io.StringWriter()
+// realex.printStackTrace(new java.io.PrintWriter(message))
+// println(message)
+ }
+ } else {
+ printout ++= reified
+ }
+ printout mkString EOL
+ }
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/Phases.scala b/src/compiler/scala/reflect/reify/Phases.scala
new file mode 100644
index 0000000000..49d5a45e8e
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/Phases.scala
@@ -0,0 +1,42 @@
+package scala.reflect
+package reify
+
+import scala.reflect.reify.phases._
+
+trait Phases extends Calculate
+ with Reshape
+ with Metalevels
+ with Reify {
+
+ self: Reifier =>
+
+ import mirror._
+ import definitions._
+
+ private var alreadyRun = false
+
+ lazy val mkReificationPipeline: Tree => Tree = tree0 => {
+ assert(!alreadyRun, "reifier instance cannot be used more than once")
+ alreadyRun = true
+
+ var tree = tree0
+
+ if (reifyDebug) println("[calculate phase]")
+ calculate.traverse(tree)
+
+ if (reifyDebug) println("[reshape phase]")
+ tree = reshape.transform(tree)
+
+ if (reifyDebug) println("[metalevels phase]")
+ tree = metalevels.transform(tree)
+
+ if (reifyDebug) println("[interlude]")
+ if (reifyDebug) println("symbol table = " + (if (symbolTable.length == 0) "<empty>" else ""))
+ if (reifyDebug) symbolTable foreach (println(_))
+ if (reifyDebug) println("reifee = " + (if (opt.showTrees) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString))
+ if (reifyDebug) println("[reify phase]")
+ var result = reify(tree)
+
+ result
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/Reifiers.scala b/src/compiler/scala/reflect/reify/Reifiers.scala
new file mode 100644
index 0000000000..16c26734b2
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/Reifiers.scala
@@ -0,0 +1,154 @@
+package scala.reflect
+package reify
+
+import scala.tools.nsc.Global
+
+/** Given a tree or a type, generate a tree that when executed at runtime produces the original tree or type.
+ * See more info in the comments to ``reify'' in scala.reflect.api.Universe.
+ *
+ * @author Martin Odersky
+ * @version 2.10
+ */
+abstract class Reifier extends Phases
+ with Errors {
+
+ val mirror: Global
+ import mirror._
+ import definitions._
+ import treeInfo._
+
+ val typer: mirror.analyzer.Typer
+ val prefix: Tree
+ val reifee: Any
+ val dontSpliceAtTopLevel: Boolean
+ val requireConcreteTypeTag: Boolean
+
+ /**
+ * For ``reifee'' and other reification parameters, generate a tree of the form
+ *
+ * {
+ * val $mr = <[ prefix ]>
+ * $mr.Expr[T](rtree) // if data is a Tree
+ * $mr.TypeTag[T](rtree) // if data is a Type
+ * }
+ *
+ * where
+ *
+ * - `prefix` is the tree that represents the universe
+ * the result will be bound to
+ * - `rtree` is code that generates `reifee` at runtime.
+ * - `T` is the type that corresponds to `data`.
+ *
+ * This is not a method, but a value to indicate the fact that Reifier instances are a one-off.
+ */
+ lazy val reified: Tree = {
+ try {
+ // [Eugene] conventional way of doing this?
+ if (prefix exists (_.isErroneous)) CannotReifyErroneousPrefix(prefix)
+ if (prefix.tpe == null) CannotReifyUntypedPrefix(prefix)
+
+ val rtree = reifee match {
+ case tree: Tree =>
+ reifyTrace("reifying = ")(if (opt.showTrees) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString)
+ reifyTrace("reifee is located at: ")(tree.pos)
+ reifyTrace("prefix = ")(prefix)
+ // [Eugene] conventional way of doing this?
+ if (tree exists (_.isErroneous)) CannotReifyErroneousReifee(prefix)
+ if (tree.tpe == null) CannotReifyUntypedReifee(tree)
+ val pipeline = mkReificationPipeline
+ val rtree = pipeline(tree)
+
+ // consider the following code snippet
+ //
+ // val x = reify { class C; new C }
+ //
+ // inferred type for x will be C
+ // but C ceases to exist after reification so this type is clearly incorrect
+ // however, reify is "just" a library function, so it cannot affect type inference
+ //
+ // hence we crash here even though the reification itself goes well
+ // fortunately, all that it takes to fix the error is to cast "new C" to Object
+ // so I'm not very much worried about introducing this restriction
+ if (tree.tpe exists (sub => sub.typeSymbol.isLocalToReifee))
+ CannotReifyReifeeThatHasTypeLocalToReifee(tree)
+
+ val manifestedType = typer.packedType(tree, NoSymbol)
+ val manifestedRtype = reifyType(manifestedType)
+ val tagModule = if (definitelyConcrete) ConcreteTypeTagModule else TypeTagModule
+ var typeTagCtor = TypeApply(Select(Ident(nme.MIRROR_SHORT), tagModule.name), List(TypeTree(manifestedType)))
+ var exprCtor = TypeApply(Select(Ident(nme.MIRROR_SHORT), ExprModule.name), List(TypeTree(manifestedType)))
+ Apply(Apply(exprCtor, List(rtree)), List(Apply(typeTagCtor, List(manifestedRtype))))
+
+ case tpe: Type =>
+ reifyTrace("reifying = ")(tpe.toString)
+ reifyTrace("prefix = ")(prefix)
+ val rtree = reify(tpe)
+
+ val manifestedType = tpe
+ var tagModule = if (definitelyConcrete) ConcreteTypeTagModule else TypeTagModule
+ var ctor = TypeApply(Select(Ident(nme.MIRROR_SHORT), tagModule.name), List(TypeTree(manifestedType)))
+ Apply(ctor, List(rtree))
+
+ case _ =>
+ throw new Error("reifee %s of type %s is not supported".format(reifee, if (reifee == null) "null" else reifee.getClass.toString))
+ }
+
+ val mirrorAlias = ValDef(NoMods, nme.MIRROR_SHORT, SingletonTypeTree(prefix), prefix)
+ val wrapped = Block(mirrorAlias :: symbolTable, rtree)
+
+ // todo. why do we resetAllAttrs?
+ //
+ // typically we do some preprocessing before reification and
+ // the code emitted/moved around during preprocessing is very hard to typecheck, so we leave it as it is
+ // however this "as it is" sometimes doesn't make any sense
+ //
+ // ===example 1===
+ // we move a freevar from a nested symbol table to a top-level symbol table,
+ // and then the reference to mr$ becomes screwed up, because nested symbol tables are already typechecked,
+ // so we have an mr$ symbol that points to the nested mr$ rather than to the top-level one.
+ //
+ // ===example 2===
+ // we inline a freevar by replacing a reference to it, e.g. $mr.Apply($mr.Select($mr.Ident($mr.newTermName("$mr")), $mr.newTermName("Ident")), List($mr.Ident($mr.newTermName("free$x"))))
+ // with its original binding (e.g. $mr.Ident("x"))
+ // we'd love to typecheck the result, but we cannot do this easily, because $mr is external to this tree
+ // what's even worse, sometimes $mr can point to the top-level symbol table's $mr, which doesn't have any symbol/type yet -
+ // it's just a ValDef that will be emitted only after the reification is completed
+ //
+ // hence, the simplest solution is to erase all attrs so that invalid (as well as non-existent) bindings get rebound correctly
+ // this is ugly, but it's the best we can do
+ //
+ // todo. this is a common problem with non-trivial macros in our current macro system
+ // needs to be solved some day
+ //
+ // list of non-hygienic transformations:
+ // 1) local freetype inlining in Nested
+ // 2) external freevar moving in Nested
+ // 3) local freeterm inlining in Metalevels
+ // 4) trivial tree splice inlining in Reify (Trees.scala)
+ // 5) trivial type splice inlining in Reify (Types.scala)
+ val freevarBindings = symbolTable collect { case freedef @ FreeDef(_, _, binding, _) => binding.symbol } toSet
+ val untyped = resetAllAttrs(wrapped, leaveAlone = {
+ case ValDef(_, mr, _, _) if mr == nme.MIRROR_SHORT => true
+ case tree if freevarBindings contains tree.symbol => true
+ case _ => false
+ })
+
+ if (reifyCopypaste) {
+ if (reifyDebug) println("=============================")
+ println(reifiedNodeToString(prefix, untyped))
+ if (reifyDebug) println("=============================")
+ } else {
+ reifyTrace("reified = ")(untyped)
+ }
+
+ untyped
+ } catch {
+ case ex: ReificationError =>
+ throw ex
+ case ex: UnexpectedReificationError =>
+ throw ex
+ case ex: Throwable =>
+ throw new UnexpectedReificationError(defaultErrorPosition, "reification crashed", ex)
+ }
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/codegen/Names.scala b/src/compiler/scala/reflect/reify/codegen/Names.scala
new file mode 100644
index 0000000000..589f6355d0
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/codegen/Names.scala
@@ -0,0 +1,15 @@
+package scala.reflect.reify
+package codegen
+
+trait Names {
+ self: Reifier =>
+
+ import mirror._
+ import definitions._
+ import treeInfo._
+
+ def reifyName(name: Name) = {
+ val factory = if (name.isTypeName) nme.nmeNewTypeName else nme.nmeNewTermName
+ mirrorCall(factory, Literal(Constant(name.toString)))
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/codegen/Positions.scala b/src/compiler/scala/reflect/reify/codegen/Positions.scala
new file mode 100644
index 0000000000..ac9195ef31
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/codegen/Positions.scala
@@ -0,0 +1,18 @@
+package scala.reflect.reify
+package codegen
+
+trait Positions {
+ self: Reifier =>
+
+ import mirror._
+ import definitions._
+ import treeInfo._
+
+ // we do not reify positions because this inflates resulting trees, but doesn't buy as anything
+ // where would one use positions? right, in error messages
+ // but I can hardly imagine when one would need a position that points to the reified code
+ // usually reified trees are used to compose macro expansions or to be fed to the runtime compiler
+ // however both macros and toolboxes have their own means to report errors in synthetic trees
+ def reifyPosition(pos: Position): Tree =
+ reifyMirrorObject(NoPosition)
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/codegen/Symbols.scala b/src/compiler/scala/reflect/reify/codegen/Symbols.scala
new file mode 100644
index 0000000000..3328f5e402
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/codegen/Symbols.scala
@@ -0,0 +1,111 @@
+package scala.reflect.reify
+package codegen
+
+trait Symbols {
+ self: Reifier =>
+
+ import mirror._
+ import definitions._
+ import treeInfo._
+
+ /** Reify a reference to a symbol */
+ def reifySymRef(sym0: Symbol): Tree = {
+ assert(sym0 != null, "sym is null")
+ val sym = sym0.dealias
+
+ if (sym == NoSymbol)
+ mirrorSelect(nme.NoSymbol)
+ else if (sym == RootPackage)
+ Select(mirrorSelect(nme.definitions), nme.RootPackage)
+ else if (sym == RootClass)
+ Select(mirrorSelect(nme.definitions), nme.RootClass)
+ else if (sym == EmptyPackage)
+ Select(mirrorSelect(nme.definitions), nme.EmptyPackage)
+ else if (sym == EmptyPackageClass)
+ Select(mirrorSelect(nme.definitions), nme.EmptyPackageClass)
+ else if (sym.isModuleClass)
+ Select(reify(sym.sourceModule), nme.moduleClass)
+ else if (sym.isLocatable) {
+ // [Eugene] am I doing this right?
+// if (sym.isStaticOwner) { // no good for us, because it returns false for packages
+ if (sym.isStatic && (sym.isClass || sym.isModule)) {
+ val resolver = if (sym.isType) nme.staticClass else nme.staticModule
+ mirrorCall(resolver, reify(sym.fullName))
+ } else {
+ if (reifyDebug) println("Locatable: %s (%s) owned by %s (%s) at %s".format(sym, sym.accurateKindString, sym.owner, sym.owner.accurateKindString, sym.owner.fullNameString))
+ val rowner = reify(sym.owner)
+ val rname = reify(sym.name.toString)
+ if (sym.isType)
+ mirrorCall(nme.selectType, rowner, rname)
+ else if (sym.isMethod && sym.owner.isClass && sym.owner.info.decl(sym.name).isOverloaded) {
+ val index = sym.owner.info.decl(sym.name).alternatives indexOf sym
+ assert(index >= 0, sym)
+ mirrorCall(nme.selectOverloadedMethod, rowner, rname, reify(index))
+ } else
+ mirrorCall(nme.selectTerm, rowner, rname)
+ }
+ } else {
+ // todo. make sure that free methods and free local defs work correctly
+ if (sym.isTerm) {
+ if (reifyDebug) println("Free term" + (if (sym.isCapturedVariable) " (captured)" else "") + ": " + sym)
+ reifyFreeTerm(sym, Ident(sym))
+ } else {
+ if (reifyDebug) println("Free type: " + sym)
+ reifyFreeType(sym, Ident(sym))
+ }
+ }
+ }
+
+ def reifyFreeTerm(sym: Symbol, value: Tree): Tree =
+ locallyReified get sym match {
+ case Some(reified) =>
+ reified
+ case None =>
+ if (sym.isCapturedVariable) {
+ assert(value.isInstanceOf[Ident], showRaw(value))
+ val capturedTpe = capturedVariableType(sym)
+ val capturedValue = referenceCapturedVariable(sym)
+ locallyReify(sym, mirrorCall(nme.newFreeTerm, reify(sym.name.toString), reify(capturedTpe), capturedValue, reify(origin(sym))))
+ } else {
+ locallyReify(sym, mirrorCall(nme.newFreeTerm, reify(sym.name.toString), reify(sym.tpe), value, reify(origin(sym))))
+ }
+ }
+
+ def reifyFreeType(sym: Symbol, value: Tree): Tree =
+ locallyReified get sym match {
+ case Some(reified) =>
+ reified
+ case None =>
+ val phantomTypeTag = Apply(TypeApply(Select(Ident(nme.MIRROR_SHORT), nme.TypeTag), List(value)), List(Literal(Constant(null))))
+ // todo. implement info reification for free types: type bounds, HK-arity, whatever else that can be useful
+ locallyReify(sym, mirrorCall(nme.newFreeType, reify(sym.name.toString), reify(sym.info), phantomTypeTag, reify(origin(sym))))
+ }
+
+ import scala.collection.mutable._
+ private val localReifications = ArrayBuffer[ValDef]()
+ private val locallyReified = Map[Symbol, Tree]()
+ def symbolTable: List[ValDef] = localReifications.toList
+ def symbolTable_=(newSymbolTable: List[ValDef]): Unit = {
+ localReifications.clear()
+ locallyReified.clear()
+ newSymbolTable foreach {
+ case freedef @ FreeDef(_, name, binding, _) =>
+ if (!(locallyReified contains binding.symbol)) {
+ localReifications += freedef
+ locallyReified(binding.symbol) = Ident(name)
+ }
+ }
+ }
+
+ private def locallyReify(sym: Symbol, reificode: => Tree): Tree = {
+ val reified = reificode
+ val Apply(Select(_, flavor), _) = reified
+ // [Eugene] name clashes are impossible, right?
+ var name = newTermName(nme.MIRROR_FREE_PREFIX + sym.name)
+ if (flavor == nme.newFreeTerm && sym.isType) name = name.append(nme.MIRROR_FREE_THIS_SUFFIX);
+ // todo. also reify annotations for free vars
+ localReifications += ValDef(NoMods, name, TypeTree(), reified)
+ locallyReified(sym) = Ident(name)
+ locallyReified(sym)
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/codegen/Trees.scala b/src/compiler/scala/reflect/reify/codegen/Trees.scala
new file mode 100644
index 0000000000..22f42aea49
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/codegen/Trees.scala
@@ -0,0 +1,220 @@
+package scala.reflect.reify
+package codegen
+
+trait Trees {
+ self: Reifier =>
+
+ import mirror._
+ import definitions._
+ import treeInfo._
+
+ /**
+ * Reify a tree.
+ * For internal use only, use ``reified'' instead.
+ */
+ def reifyTree(tree: Tree): Tree = {
+ assert(tree != null, "tree is null")
+
+ if (tree.isErroneous)
+ CannotReifyErroneousReifee(tree)
+
+ val splicedTree = spliceTree(tree)
+ if (splicedTree != EmptyTree)
+ return splicedTree
+
+ // the idea behind the new reincarnation of reifier is a simple maxim:
+ //
+ // never call ``reifyType'' to reify a tree
+ //
+ // this works because the stuff we are reifying was once represented with trees only
+ // and lexical scope information can be fully captured by reifying symbols
+ //
+ // to enable this idyll, we work hard in the ``Reshape'' phase
+ // which replaces all types with equivalent trees and works around non-idempotencies of the typechecker
+ //
+ // why bother? because this brings method to the madness
+ // the first prototype of reification reified all types and symbols for all trees => this quickly became unyieldy
+ // the second prototype reified external types, but avoided reifying local ones => this created an ugly irregularity
+ // current approach is uniform and compact
+ var rtree = tree match {
+ case mirror.EmptyTree =>
+ reifyMirrorObject(EmptyTree)
+ case mirror.emptyValDef =>
+ mirrorSelect(nme.emptyValDef)
+ case FreeDef(_, _, _, _) =>
+ reifyNestedFreeDef(tree)
+ case FreeRef(_, _) =>
+ reifyNestedFreeRef(tree)
+ case BoundTerm(tree) =>
+ reifyBoundTerm(tree)
+ case BoundType(tree) =>
+ reifyBoundType(tree)
+ case NestedExpr(_, _, _) =>
+ reifyNestedExpr(tree)
+ case Literal(const @ Constant(_)) =>
+ mirrorCall(nme.Literal, reifyProduct(const))
+ case Import(expr, selectors) =>
+ mirrorCall(nme.Import, reify(expr), mkList(selectors map reifyProduct))
+ case _ =>
+ reifyProduct(tree)
+ }
+
+ rtree
+ }
+
+ def reifyModifiers(m: mirror.Modifiers) =
+ mirrorCall("modifiersFromInternalFlags", reify(m.flags), reify(m.privateWithin), reify(m.annotations))
+
+ private def spliceTree(tree: Tree): Tree = {
+ tree match {
+ case EvalSplice(splicee) =>
+ if (reifyDebug) println("splicing eval " + tree)
+
+ // see ``Metalevels'' for more info about metalevel breaches
+ // and about how we deal with splices that contain them
+ if (splicee exists (sub => sub.hasSymbol && sub.symbol != NoSymbol && sub.symbol.metalevel > 0)) {
+ if (reifyDebug) println("splicing has failed: cannot splice when facing a metalevel breach")
+ EmptyTree
+ } else {
+ if (reifyDebug) println("splicing has succeeded")
+ var splice = Select(splicee, nme.tree)
+ splice match {
+ case InlinedTreeSplice(_, inlinedSymbolTable, tree, _) =>
+ if (reifyDebug) println("inlining the splicee")
+ // all free vars local to the enclosing reifee should've already been inlined by ``Metalevels''
+ inlinedSymbolTable foreach { case freedef @ FreeDef(_, _, binding, _) => assert(!binding.symbol.isLocalToReifee, freedef) }
+ symbolTable ++= inlinedSymbolTable
+ tree
+ case tree =>
+ // we need to preserve types of exprs, because oftentimes they cannot be inferred later
+ // this circumvents regular reification scheme, therefore we go the extra mile here
+ new Transformer {
+ override def transform(tree: Tree) = super.transform(tree match {
+ case NestedExpr(factory, tree, typetag) =>
+ val typedFactory = TypeApply(factory, List(TypeTree(typetag.tpe.typeArgs(0))))
+ Apply(Apply(typedFactory, List(tree)), List(typetag))
+ case _ =>
+ tree
+ })
+ }.transform(tree)
+ }
+ }
+ case ValueSplice(splicee) =>
+ // todo. implement this
+ ???
+ case _ =>
+ EmptyTree
+ }
+ }
+
+ private def reifyBoundTerm(tree: Tree): Tree = tree match {
+ case tree @ This(_) if tree.symbol == NoSymbol =>
+ throw new Error("unexpected: bound term that doesn't have a symbol: " + showRaw(tree))
+ case tree @ This(_) if tree.symbol.isClass && !tree.symbol.isModuleClass && !tree.symbol.isLocalToReifee =>
+ val sym = tree.symbol
+ if (reifyDebug) println("This for %s, reified as freeVar".format(sym))
+ if (reifyDebug) println("Free: " + sym)
+ mirrorCall(nme.Ident, reifyFreeTerm(sym, This(sym)))
+ case tree @ This(_) if !tree.symbol.isLocalToReifee =>
+ if (reifyDebug) println("This for %s, reified as This".format(tree.symbol))
+ mirrorCall(nme.This, reify(tree.symbol))
+ case tree @ This(_) if tree.symbol.isLocalToReifee =>
+ mirrorCall(nme.This, reify(tree.qual))
+ case tree @ Ident(_) if tree.symbol == NoSymbol =>
+ // this sometimes happens, e.g. for binds that don't have a body
+ // or for untyped code generated during previous phases
+ // (see a comment in Reifiers about the latter, starting with "why do we resetAllAttrs?")
+ mirrorCall(nme.Ident, reify(tree.name))
+ case tree @ Ident(_) if !tree.symbol.isLocalToReifee =>
+ if (tree.symbol.isVariable && tree.symbol.owner.isTerm) {
+ captureVariable(tree.symbol) // Note order dependency: captureVariable needs to come before reification here.
+ mirrorCall(nme.Select, mirrorCall(nme.Ident, reify(tree.symbol)), reify(nme.elem))
+ } else {
+ mirrorCall(nme.Ident, reify(tree.symbol))
+ }
+ case tree @ Ident(_) if tree.symbol.isLocalToReifee =>
+ mirrorCall(nme.Ident, reify(tree.name))
+ case _ =>
+ throw new Error("internal error: %s (%s, %s) is not supported".format(tree, tree.productPrefix, tree.getClass))
+ }
+
+ private def reifyBoundType(tree: Tree): Tree = {
+ def reifyBoundType(tree: Tree): Tree = {
+ if (tree.tpe == null)
+ throw new Error("unexpected: bound type that doesn't have a tpe: " + showRaw(tree))
+
+ if (tree.symbol.isLocalToReifee)
+ reifyProduct(tree)
+ else {
+ val sym0 = tree.symbol
+ val sym = sym0.dealias
+ val tpe0 = tree.tpe
+ val tpe = tpe0.dealias
+ if (reifyDebug) println("reifying bound type %s (underlying type is %s, dealiased is %s)".format(sym0, tpe0, tpe))
+
+ if (eligibleForSplicing(tpe)) {
+ val spliced = spliceType(tpe)
+ if (spliced == EmptyTree) {
+ if (reifyDebug) println("splicing failed: reify as is")
+ mirrorCall(nme.TypeTree, reifyType(tpe))
+ } else {
+ spliced match {
+ case TypeRefToFreeType(freeType) =>
+ if (reifyDebug) println("splicing returned a free type: " + freeType)
+ Ident(freeType)
+ case _ =>
+ if (reifyDebug) println("splicing succeeded: " + spliced)
+ mirrorCall(nme.TypeTree, spliced)
+ }
+ }
+ } else {
+ if (sym.isLocatable) {
+ if (reifyDebug) println("tpe is locatable: reify as Ident(%s)".format(sym))
+ mirrorCall(nme.Ident, reify(sym))
+ } else {
+ if (reifyDebug) println("tpe is an alias, but not a locatable: reify as TypeTree(%s)".format(tpe))
+ mirrorCall(nme.TypeTree, reifyType(tpe))
+ }
+ }
+ }
+ }
+
+ tree match {
+ case Select(_, _) =>
+ reifyBoundType(tree)
+ case SelectFromTypeTree(_, _) =>
+ reifyBoundType(tree)
+ case Ident(_) =>
+ reifyBoundType(tree)
+ case _ =>
+ throw new Error("internal error: %s (%s, %s) is not supported".format(tree, tree.productPrefix, tree.getClass))
+ }
+ }
+
+ private def reifyNestedFreeDef(tree: Tree): Tree = {
+ if (reifyDebug) println("nested free def: %s".format(showRaw(tree)))
+ reifyProduct(tree)
+ }
+
+ private def reifyNestedFreeRef(tree: Tree): Tree = tree match {
+ case Apply(Select(mrRef @ Ident(_), ident), List(Ident(name: TermName))) if ident == nme.Ident && name.startsWith(nme.MIRROR_FREE_PREFIX) =>
+ if (reifyDebug) println("nested free ref: %s".format(showRaw(tree)))
+ reifyProduct(tree)
+ case _ =>
+ throw new Error("internal error: %s (%s, %s) is not supported".format(tree, tree.productPrefix, tree.getClass))
+ }
+
+ private def reifyNestedExpr(tree: Tree): Tree = tree match {
+ case NestedExpr(factory, tree, typetag) =>
+ // we need to preserve types of exprs, because oftentimes they cannot be inferred later
+ // this circumvents regular reification scheme, therefore we go through this crazy dance
+ if (reifyDebug) println("nested expr: %s".format(showRaw(tree)))
+ val rtype = mirrorCall(nme.TypeTree, reify(typetag.tpe.typeArgs(0)))
+ val rfactory = mirrorCall(nme.TypeApply, reify(factory), mkList(List(rtype)))
+ val rexpr = mirrorCall(nme.Apply, rfactory, reify(List(tree)))
+ val rwrapped = mirrorCall(nme.Apply, rexpr, reify(List(typetag)))
+ rwrapped
+ case _ =>
+ throw new Error("internal error: %s (%s, %s) is not supported".format(tree, tree.productPrefix, tree.getClass))
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/codegen/Types.scala b/src/compiler/scala/reflect/reify/codegen/Types.scala
new file mode 100644
index 0000000000..9bc113e8a4
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/codegen/Types.scala
@@ -0,0 +1,226 @@
+package scala.reflect.reify
+package codegen
+
+trait Types {
+ self: Reifier =>
+
+ import mirror._
+ import definitions._
+ import treeInfo._
+
+ /**
+ * Reify a type.
+ * For internal use only, use ``reified'' instead.
+ */
+ def reifyType(tpe0: Type): Tree = {
+ assert(tpe0 != null, "tpe is null")
+ val tpe = tpe0.dealias
+
+ if (tpe.isErroneous)
+ CannotReifyErroneousReifee(tpe)
+ if (tpe.isLocalToReifee)
+ CannotReifyType(tpe)
+
+ // [Eugene] how do I check that the substitution is legal w.r.t tpe.info?
+ val spliced = spliceType(tpe)
+ if (spliced != EmptyTree)
+ return spliced
+
+ val tsym = tpe.typeSymbol
+ if (tsym.isClass && tpe == tsym.typeConstructor && tsym.isStatic)
+ Select(reify(tpe.typeSymbol), nme.asTypeConstructor)
+ else tpe match {
+ case tpe @ NoType =>
+ reifyMirrorObject(tpe)
+ case tpe @ NoPrefix =>
+ reifyMirrorObject(tpe)
+ case tpe @ ThisType(root) if root == RootClass =>
+ mirrorSelect("definitions.RootClass.thisPrefix")
+ case tpe @ ThisType(empty) if empty == EmptyPackageClass =>
+ mirrorSelect("definitions.EmptyPackageClass.thisPrefix")
+ case tpe @ ThisType(clazz) if clazz.isModuleClass && clazz.isStatic =>
+ mirrorCall(nme.thisModuleType, reify(clazz.fullName))
+ case tpe @ ThisType(_) =>
+ reifyProduct(tpe)
+ case tpe @ SuperType(thistpe, supertpe) =>
+ reifyProduct(tpe)
+ case tpe @ SingleType(pre, sym) =>
+ reifyProduct(tpe)
+ case tpe @ ConstantType(value) =>
+ mirrorFactoryCall(nme.ConstantType, reifyProduct(value))
+ case tpe @ TypeRef(pre, sym, args) =>
+ reifyProduct(tpe)
+ case tpe @ TypeBounds(lo, hi) =>
+ reifyProduct(tpe)
+ case tpe @ NullaryMethodType(restpe) =>
+ reifyProduct(tpe)
+ case tpe @ AnnotatedType(anns, underlying, selfsym) =>
+// reifyAnnotatedType(tpe)
+ CannotReifyType(tpe)
+ case _ =>
+// reifyToughType(tpe)
+ CannotReifyType(tpe)
+ }
+ }
+
+ /** An obscure flag necessary for implicit TypeTag generation */
+ private var spliceTypesEnabled = !dontSpliceAtTopLevel
+
+ /** Keeps track of whether this reification contains abstract type parameters */
+ var maybeConcrete = true
+ var definitelyConcrete = true
+
+ def eligibleForSplicing(tpe: Type): Boolean = {
+ // [Eugene] is this comprehensive?
+ // the only thingies that we want to splice are: 1) type parameters, 2) type members
+ // this check seems to cover them all, right?
+ tpe.isInstanceOf[TypeRef] && tpe.typeSymbol.isAbstractType
+ }
+
+ private type SpliceCacheKey = (Symbol, Symbol)
+ private lazy val spliceCache: collection.mutable.Map[SpliceCacheKey, Tree] = {
+ val cache = analyzer.perRunMacroCache.getOrElseUpdate(MacroContextReify, collection.mutable.Map[Any, Any]())
+ cache.getOrElseUpdate("spliceCache", collection.mutable.Map[SpliceCacheKey, Tree]()).asInstanceOf[collection.mutable.Map[SpliceCacheKey, Tree]]
+ }
+
+ def spliceType(tpe: Type): Tree = {
+ if (eligibleForSplicing(tpe)) {
+ if (reifyDebug) println("splicing " + tpe)
+
+ if (spliceTypesEnabled) {
+ var tagClass = if (requireConcreteTypeTag) ConcreteTypeTagClass else TypeTagClass
+ val tagTpe = singleType(prefix.tpe, prefix.tpe member tagClass.name)
+
+ // [Eugene] this should be enough for an abstract type, right?
+ val key = (tagClass, tpe.typeSymbol)
+ if (reifyDebug && spliceCache.contains(key)) println("cache hit: " + spliceCache(key))
+ val result = spliceCache.getOrElseUpdate(key, {
+ // if this fails, it might produce the dreaded "erroneous or inaccessible type" error
+ // to find out the whereabouts of the error run scalac with -Ydebug
+ if (reifyDebug) println("launching implicit search for %s.%s[%s]".format(prefix, tagClass.name, tpe))
+ val positionBearer = mirror.analyzer.openMacros.find(c => c.macroApplication.pos != NoPosition).map(_.macroApplication).getOrElse(EmptyTree).asInstanceOf[Tree]
+ typer.resolveTypeTag(positionBearer, prefix.tpe, tpe, requireConcreteTypeTag) match {
+ case failure if failure.isEmpty =>
+ if (reifyDebug) println("implicit search was fruitless")
+ definitelyConcrete &= false
+ maybeConcrete &= false
+ EmptyTree
+ case success =>
+ if (reifyDebug) println("implicit search has produced a result: " + success)
+ definitelyConcrete |= requireConcreteTypeTag
+ maybeConcrete |= true
+ var splice = Select(success, nme.tpe)
+ splice match {
+ case InlinedTypeSplice(_, inlinedSymbolTable, tpe) =>
+ // all free vars local to the enclosing reifee should've already been inlined by ``Metalevels''
+ inlinedSymbolTable foreach { case freedef @ FreeDef(_, _, binding, _) => assert(!binding.symbol.isLocalToReifee, freedef) }
+ symbolTable ++= inlinedSymbolTable
+ reifyTrace("inlined the splicee: ")(tpe)
+ case tpe =>
+ tpe
+ }
+ }
+ })
+ if (result != EmptyTree) return result.duplicate
+ } else {
+ if (reifyDebug) println("splicing has been cancelled: spliceTypesEnabled = false")
+ }
+
+ if (requireConcreteTypeTag)
+ CannotReifyConcreteTypeTagHavingUnresolvedTypeParameters(tpe)
+ }
+
+ spliceTypesEnabled = true
+ EmptyTree
+ }
+
+ // yet another thingie disabled for simplicity
+ // in principle, we could retain and reify AnnotatedTypes
+ // but that'd require reifying every type and symbol inside ann.args
+ // however, since we've given up on tough types for the moment, the former would be problematic
+// private def reifyAnnotatedType(tpe: AnnotatedType): Tree = {
+// // ``Reshaper'' transforms annotation infos from symbols back into Modifier.annotations, which are trees
+// // so the only place on Earth that can lead to reification of AnnotationInfos is the Ay Tee Land
+// // therefore this function is as local as possible, don't move it out of this scope
+// def reifyAnnotationInfo(ann: AnnotationInfo): Tree = {
+// val reifiedArgs = ann.args map { arg =>
+// val saved1 = reifyTreeSymbols
+// val saved2 = reifyTreeTypes
+//
+// try {
+// // one more quirk of reifying annotations
+// //
+// // when reifying AnnotatedTypes we need to reify all the types and symbols of inner ASTs
+// // that's because a lot of logic expects post-typer trees to have non-null tpes
+// //
+// // Q: reified trees are pre-typer, so there's shouldn't be a problem.
+// // reflective typechecker will fill in missing symbols and types, right?
+// // A: actually, no. annotation ASTs live inside AnnotatedTypes,
+// // and insides of the types is the place where typechecker doesn't look.
+// reifyTreeSymbols = true
+// reifyTreeTypes = true
+//
+// // todo. every AnnotationInfo is an island, entire of itself
+// // no regular Traverser or Transformer can reach it
+// // hence we need to run its contents through the entire reification pipeline
+// // e.g. to apply reshaping or to check metalevels
+// reify(arg)
+// } finally {
+// reifyTreeSymbols = saved1
+// reifyTreeTypes = saved2
+// }
+// }
+//
+// def reifyClassfileAnnotArg(arg: ClassfileAnnotArg): Tree = arg match {
+// case LiteralAnnotArg(const) =>
+// mirrorFactoryCall(nme.LiteralAnnotArg, reifyProduct(const))
+// case ArrayAnnotArg(args) =>
+// mirrorFactoryCall(nme.ArrayAnnotArg, scalaFactoryCall(nme.Array, args map reifyClassfileAnnotArg: _*))
+// case NestedAnnotArg(ann) =>
+// mirrorFactoryCall(nme.NestedAnnotArg, reifyAnnotationInfo(ann))
+// }
+//
+// // if you reify originals of anns, you get SO when trying to reify AnnotatedTypes, so screw it - after all, it's not that important
+// val reifiedAssocs = ann.assocs map (assoc => scalaFactoryCall(nme.Tuple2, reify(assoc._1), reifyClassfileAnnotArg(assoc._2)))
+// mirrorFactoryCall(nme.AnnotationInfo, reify(ann.atp), mkList(reifiedArgs), mkList(reifiedAssocs))
+// }
+//
+// val AnnotatedType(anns, underlying, selfsym) = tpe
+// mirrorFactoryCall(nme.AnnotatedType, mkList(anns map reifyAnnotationInfo), reify(underlying), reify(selfsym))
+// }
+
+ // previous solution to reifying tough types involved creating dummy symbols (see ``registerReifiableSymbol'' calls below)
+ // however such symbols lost all the connections with their origins and became almost useless, except for typechecking
+ // hence this approach was replaced by less powerful, but more principled one based on ``reifyFreeType''
+ // it's possible that later on we will revise and revive ``reifyToughType'', but for now it's disabled under an implementation restriction
+// /** Reify a tough type, i.e. the one that leads to creation of auxiliary symbols */
+// // This is the uncharted territory in the reifier
+// private def reifyToughType(tpe: Type): Tree = {
+// if (reifyDebug) println("tough type: %s (%s)".format(tpe, tpe.kind))
+//
+// def reifyScope(scope: Scope): Tree = {
+// scope foreach registerReifiableSymbol
+// mirrorCall(nme.newScopeWith, scope.toList map reify: _*)
+// }
+//
+// tpe match {
+// case tpe @ RefinedType(parents, decls) =>
+// registerReifiableSymbol(tpe.typeSymbol)
+// mirrorFactoryCall(tpe, reify(parents), reifyScope(decls), reify(tpe.typeSymbol))
+// case tpe @ ExistentialType(tparams, underlying) =>
+// tparams foreach registerReifiableSymbol
+// mirrorFactoryCall(tpe, reify(tparams), reify(underlying))
+// case tpe @ ClassInfoType(parents, decls, clazz) =>
+// registerReifiableSymbol(clazz)
+// mirrorFactoryCall(tpe, reify(parents), reifyScope(decls), reify(tpe.typeSymbol))
+// case tpe @ MethodType(params, restpe) =>
+// params foreach registerReifiableSymbol
+// mirrorFactoryCall(tpe, reify(params), reify(restpe))
+// case tpe @ PolyType(tparams, underlying) =>
+// tparams foreach registerReifiableSymbol
+// mirrorFactoryCall(tpe, reify(tparams), reify(underlying))
+// case _ =>
+// throw new Error("internal error: %s (%s) is not supported".format(tpe, tpe.kind))
+// }
+// }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/codegen/Util.scala b/src/compiler/scala/reflect/reify/codegen/Util.scala
new file mode 100644
index 0000000000..bb369a1adb
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/codegen/Util.scala
@@ -0,0 +1,112 @@
+package scala.reflect.reify
+package codegen
+
+trait Util {
+ self: Reifier =>
+
+ import mirror._
+ import definitions._
+ import treeInfo._
+
+ val reifyDebug = settings.Yreifydebug.value
+ val reifyCopypaste = settings.Yreifycopypaste.value
+ val reifyTrace = scala.tools.nsc.util.trace when reifyDebug
+ object reifiedNodePrinters extends { val global: mirror.type = mirror } with tools.nsc.ast.NodePrinters with NodePrinters
+ val reifiedNodeToString = reifiedNodePrinters.reifiedNodeToString
+
+ def reifyList(xs: List[Any]): Tree =
+ mkList(xs map reify)
+
+ def reifyProduct(x: Product): Tree =
+ reifyProduct(x.productPrefix, x.productIterator.toList)
+
+ def reifyProduct(prefix: String, elements: List[Any]): Tree = {
+ // reflection would be more robust, but, hey, this is a hot path
+ if (prefix.startsWith("Tuple")) scalaFactoryCall(prefix, (elements map reify).toList: _*)
+ else mirrorCall(prefix, (elements map reify): _*)
+ }
+
+ // helper functions
+
+ /** Reify a case object defined in Mirror */
+ def reifyMirrorObject(name: String): Tree =
+ mirrorSelect(name)
+
+ def reifyMirrorObject(x: Product): Tree =
+ reifyMirrorObject(x.productPrefix)
+
+ def call(fname: String, args: Tree*): Tree =
+ Apply(termPath(fname), args.toList)
+
+ def mirrorSelect(name: String): Tree =
+ termPath(nme.MIRROR_PREFIX + name)
+
+ def mirrorCall(name: TermName, args: Tree*): Tree =
+ call("" + (nme.MIRROR_PREFIX append name), args: _*)
+
+ def mirrorCall(name: String, args: Tree*): Tree =
+ call(nme.MIRROR_PREFIX + name, args: _*)
+
+ def mirrorFactoryCall(value: Product, args: Tree*): Tree =
+ mirrorFactoryCall(value.productPrefix, args: _*)
+
+ def mirrorFactoryCall(prefix: String, args: Tree*): Tree =
+ mirrorCall(prefix, args: _*)
+
+ def scalaFactoryCall(name: String, args: Tree*): Tree =
+ call("scala." + name + ".apply", args: _*)
+
+ def mkList(args: List[Tree]): Tree =
+ scalaFactoryCall("collection.immutable.List", args: _*)
+
+ /**
+ * An (unreified) path that refers to definition with given fully qualified name
+ * @param mkName Creator for last portion of name (either TermName or TypeName)
+ */
+ def path(fullname: String, mkName: String => Name): Tree = {
+ val parts = fullname split "\\."
+ val prefixParts = parts.init
+ val lastName = mkName(parts.last)
+ if (prefixParts.isEmpty) Ident(lastName)
+ else {
+ val prefixTree = ((Ident(prefixParts.head): Tree) /: prefixParts.tail)(Select(_, _))
+ Select(prefixTree, lastName)
+ }
+ }
+
+ /** An (unreified) path that refers to term definition with given fully qualified name */
+ def termPath(fullname: String): Tree = path(fullname, newTermName)
+
+ /** An (unreified) path that refers to type definition with given fully qualified name */
+ def typePath(fullname: String): Tree = path(fullname, newTypeName)
+
+ def isTough(tpe: Type) = {
+ def isTough(tpe: Type) = tpe match {
+ case _: RefinedType => true
+ case _: ExistentialType => true
+ case _: ClassInfoType => true
+ case _: MethodType => true
+ case _: PolyType => true
+ case _ => false
+ }
+
+ tpe != null && (tpe exists isTough)
+ }
+
+ def isAnnotated(tpe: Type) = {
+ def isAnnotated(tpe: Type) = tpe match {
+ case _: AnnotatedType => true
+ case _ => false
+ }
+
+ tpe != null && (tpe exists isAnnotated)
+ }
+
+ def origin(sym: Symbol) = {
+ var origin = ""
+ if (sym.owner != NoSymbol) origin += "defined by %s".format(sym.owner.name)
+ if (sym.pos != NoPosition) origin += " in %s:%s:%s".format(sym.pos.source.file.name, sym.pos.line, sym.pos.column)
+ if (origin == "") origin = "of unknown origin"
+ origin
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/package.scala b/src/compiler/scala/reflect/reify/package.scala
new file mode 100644
index 0000000000..85cf92fe2f
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/package.scala
@@ -0,0 +1,22 @@
+package scala.reflect
+
+import scala.tools.nsc.Global
+
+package object reify {
+ def mkReifier(global: Global)(typer: global.analyzer.Typer, prefix: global.Tree, reifee: Any, dontSpliceAtTopLevel: Boolean = false, requireConcreteTypeTag: Boolean = false): Reifier { val mirror: global.type } = {
+ val typer1: typer.type = typer
+ val prefix1: prefix.type = prefix
+ val reifee1 = reifee
+ val dontSpliceAtTopLevel1 = dontSpliceAtTopLevel
+ val requireConcreteTypeTag1 = requireConcreteTypeTag
+
+ new {
+ val mirror: global.type = global
+ val typer = typer1
+ val prefix = prefix1
+ val reifee = reifee1
+ val dontSpliceAtTopLevel = dontSpliceAtTopLevel1
+ val requireConcreteTypeTag = requireConcreteTypeTag1
+ } with Reifier
+ }
+}
diff --git a/src/compiler/scala/reflect/reify/phases/Calculate.scala b/src/compiler/scala/reflect/reify/phases/Calculate.scala
new file mode 100644
index 0000000000..59a36f0ba4
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/phases/Calculate.scala
@@ -0,0 +1,61 @@
+package scala.reflect.reify
+package phases
+
+trait Calculate {
+ self: Reifier =>
+
+ import mirror._
+ import definitions._
+ import treeInfo._
+
+ implicit def sym2richSym(sym: Symbol): RichSymbol = new RichSymbol(sym)
+ class RichSymbol(sym: Symbol) {
+ def metalevel: Int = { assert(sym != NoSymbol); localSymbols.getOrElse(sym, 0) }
+ def isLocalToReifee = (localSymbols contains sym) // [Eugene] how do I account for local skolems?
+ }
+
+ implicit def tpe2richTpe(tpe: Type): RichType = new RichType(tpe)
+ class RichType(tpe: Type) {
+ def isLocalToReifee = tpe != null && (tpe exists (tp => (localSymbols contains tp.typeSymbol) || (localSymbols contains tp.termSymbol)))
+ }
+
+ private var localSymbols = collection.mutable.Map[Symbol, Int]() // set of all symbols that are local to the tree to be reified
+ private def registerLocalSymbol(sym: Symbol, metalevel: Int): Unit =
+ if (sym != null && sym != NoSymbol) {
+ if (localSymbols contains sym)
+ assert(localSymbols(sym) == metalevel, "metalevel mismatch: expected %s, actual %s".format(localSymbols(sym), metalevel))
+ localSymbols(sym) = metalevel
+ }
+
+ /**
+ * Merely traverses the reifiee and records local symbols along with their metalevels.
+ */
+ val calculate = new Traverser {
+ // see the explanation of metalevels in ``Metalevels''
+ var currMetalevel = 1
+
+ override def traverse(tree: Tree): Unit = tree match {
+ case TreeSplice(_) =>
+ currMetalevel -= 1
+ try super.traverse(tree)
+ finally currMetalevel += 1
+ case tree if tree.isDef =>
+ if (reifyDebug) println("boundSym: %s of type %s".format(tree.symbol, (tree.productIterator.toList collect { case tt: TypeTree => tt } headOption).getOrElse(TypeTree(tree.tpe))))
+ registerLocalSymbol(tree.symbol, currMetalevel)
+
+ bindRelatedSymbol(tree.symbol.sourceModule, "sourceModule")
+ bindRelatedSymbol(tree.symbol.moduleClass, "moduleClass")
+ bindRelatedSymbol(tree.symbol.companionClass, "companionClass")
+ bindRelatedSymbol(tree.symbol.companionModule, "companionModule")
+ Some(tree.symbol) collect { case termSymbol: TermSymbol => bindRelatedSymbol(termSymbol.referenced, "referenced") }
+ def bindRelatedSymbol(related: Symbol, name: String): Unit =
+ if (related != null && related != NoSymbol) {
+ if (reifyDebug) println("boundSym (" + name + "): " + related)
+ registerLocalSymbol(related, currMetalevel)
+ }
+ super.traverse(tree)
+ case _ =>
+ super.traverse(tree)
+ }
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/phases/Metalevels.scala b/src/compiler/scala/reflect/reify/phases/Metalevels.scala
new file mode 100644
index 0000000000..a329a1043d
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/phases/Metalevels.scala
@@ -0,0 +1,148 @@
+package scala.reflect.reify
+package phases
+
+trait Metalevels {
+ self: Reifier =>
+
+ import mirror._
+ import definitions._
+ import treeInfo._
+
+ /**
+ * Makes sense of cross-stage bindings.
+ *
+ * ================
+ *
+ * Analysis of cross-stage bindings becomes convenient if we introduce the notion of metalevels.
+ * Metalevel of a tree is a number that gets incremented every time you reify something and gets decremented when you splice something.
+ * Metalevel of a symbol is equal to the metalevel of its definition.
+ *
+ * Example 1. Consider the following snippet:
+ *
+ * reify {
+ * val x = 2 // metalevel of symbol x is 1, because it's declared inside reify
+ * val y = reify{x} // metalevel of symbol y is 1, because it's declared inside reify
+ * // metalevel of Ident(x) is 2, because it's inside two reifies
+ * y.eval // metalevel of Ident(y) is 0, because it's inside a designator of a splice
+ * }
+ *
+ * Cross-stage bindings are introduced when symbol.metalevel != curr_metalevel.
+ * Both bindings introduced in Example 1 are cross-stage.
+ *
+ * Depending on what side of the inequality is greater, the following situations might occur:
+ *
+ * 1) symbol.metalevel < curr_metalevel. In this case reifier will generate a free variable
+ * that captures both the name of the symbol (to be compiled successfully) and its value (to be run successfully).
+ * For example, x in Example 1 will be reified as follows: Ident(newFreeVar("x", IntClass.tpe, x))
+ *
+ * 2) symbol.metalevel > curr_metalevel. This leads to a metalevel breach that violates intuitive perception of splicing.
+ * As defined in macro spec, splicing takes a tree and inserts it into another tree - as simple as that.
+ * However, how exactly do we do that in the case of y.eval? In this very scenario we can use dataflow analysis and inline it,
+ * but what if y were a var, and what if it were calculated randomly at runtime?
+ *
+ * This question has a genuinely simple answer. Sure, we cannot resolve such splices statically (i.e. during macro expansion of ``reify''),
+ * but now we have runtime toolboxes, so noone stops us from picking up that reified tree and evaluating it at runtime
+ * (in fact, this is something that ``Expr.eval'' and ``Expr.value'' do transparently).
+ *
+ * This is akin to early vs late binding dilemma.
+ * The prior is faster, plus, the latter (implemented with reflection) might not work because of visibility issues or might be not available on all platforms.
+ * But the latter still has its uses, so I'm allowing metalevel breaches, but introducing the -Xlog-runtime-evals to log them.
+ *
+ * ================
+ *
+ * As we can see, the only problem is the fact that lhs'es of eval can be code blocks that can capture variables from the outside.
+ * Code inside the lhs of an eval is not reified, while the code from the enclosing reify is.
+ *
+ * Hence some bindings become cross-stage, which is not bad per se (in fact, some cross-stage bindings have sane semantics, as in the example above).
+ * However this affects freevars, since they are delicate inter-dimensional beings that refer to both current and next planes of existence.
+ * When splicing tears the fabric of the reality apart, some freevars have to go single-dimensional to retain their sanity.
+ *
+ * Example 2. Consider the following snippet:
+ *
+ * reify {
+ * val x = 2
+ * reify{x}.eval
+ * }
+ *
+ * Since the result of the inner reify is wrapped in an eval, it won't be reified
+ * together with the other parts of the outer reify, but will be inserted into that result verbatim.
+ *
+ * The inner reify produces an Expr[Int] that wraps Ident(freeVar("x", IntClass.tpe, x)).
+ * However the freevar the reification points to will vanish when the compiler processes the outer reify.
+ * That's why we need to replace that freevar with a regular symbol that will point to reified x.
+ *
+ * Example 3. Consider the following fragment:
+ *
+ * reify {
+ * val x = 2
+ * val y = reify{x}
+ * y.eval
+ * }
+ *
+ * In this case the inner reify doesn't appear next to eval, so it will be reified together with x.
+ * This means that no special processing is needed here.
+ *
+ * Example 4. Consider the following fragment:
+ *
+ * reify {
+ * val x = 2
+ * {
+ * val y = 2
+ * val z = reify{reify{x + y}}
+ * z.eval
+ * }.eval
+ * }
+ *
+ * The reasoning from Example 2 still holds here - we do need to inline the freevar that refers to x.
+ * However, we must not touch anything inside the eval'd block, because it's not getting reified.
+ */
+ var metalevels = new Transformer {
+ var insideSplice = false
+ var freedefsToInline = collection.mutable.Map[String, ValDef]()
+
+ def withinSplice[T](op: => T) = {
+ val old = insideSplice
+ insideSplice = true
+ try op
+ finally insideSplice = old
+ }
+
+ // Q: here we deal with all sorts of reified trees. what about ReifiedType(_, _, _, _)?
+ // A: nothing. reified trees give us problems because they sometimes create dimensional rifts as described above
+ // to the contrast, reified types (i.e. synthetic typetags materialized by Implicits.scala) always stay on the same metalevel as their enclosing code
+ override def transform(tree: Tree): Tree = tree match {
+ case InlineableTreeSplice(splicee, inlinedSymbolTable, _, _, flavor) =>
+ if (reifyDebug) println("entering inlineable splice: " + splicee)
+ val Block(mrDef :: symbolTable, expr) = splicee
+ // [Eugene] how to express the fact that a scrutinee is both of some type and matches an extractor?
+ val freedefsToInline = symbolTable collect { case freedef @ FreeTermDef(_, _, binding, _) if binding.symbol.isLocalToReifee => freedef.asInstanceOf[ValDef] }
+ freedefsToInline foreach (vdef => this.freedefsToInline(vdef.name) = vdef)
+ val symbolTable1 = symbolTable diff freedefsToInline
+ val tree1 = Select(Block(mrDef :: symbolTable1, expr), flavor)
+ if (reifyDebug) println("trimmed %s inlineable free defs from its symbol table: %s".format(freedefsToInline.length, freedefsToInline map (_.name) mkString(", ")))
+ withinSplice { super.transform(tree1) }
+ case TreeSplice(splicee) =>
+ if (reifyDebug) println("entering splice: " + splicee)
+ val hasBreaches = splicee exists (_.symbol.metalevel > 0)
+ if (!insideSplice && hasBreaches) {
+ if (settings.logRuntimeSplices.value) reporter.echo(tree.pos, "this splice cannot be resolved statically")
+ if (reifyDebug) println("metalevel breach in %s: %s".format(tree, (splicee filter (_.symbol.metalevel > 0) map (_.symbol) distinct) mkString ", "))
+ }
+ withinSplice { super.transform(tree) }
+ // todo. also inline usages of ``freedefsToInline'' in the symbolTable itself
+ // e.g. a free$Foo can well use free$x, if Foo is path-dependent w.r.t x
+ // FreeRef(_, _) check won't work, because metalevels of symbol table and body are different, hence, freerefs in symbol table look different from freerefs in body
+ // todo. also perform garbage collection on local symbols
+ // so that local symbols used only in type signatures of free vars get removed
+ case FreeRef(mr, name) if freedefsToInline contains name =>
+ if (reifyDebug) println("inlineable free ref: %s in %s".format(name, showRaw(tree)))
+ val freedef @ FreeDef(_, _, binding, _) = freedefsToInline(name)
+ if (reifyDebug) println("related definition: %s".format(showRaw(freedef)))
+ val inlined = reify(binding)
+ if (reifyDebug) println("verdict: inlined as %s".format(showRaw(inlined)))
+ inlined
+ case _ =>
+ super.transform(tree)
+ }
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/phases/Reify.scala b/src/compiler/scala/reflect/reify/phases/Reify.scala
new file mode 100644
index 0000000000..f6d6423605
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/phases/Reify.scala
@@ -0,0 +1,42 @@
+package scala.reflect.reify
+package phases
+
+import scala.runtime.ScalaRunTime.isAnyVal
+import scala.runtime.ScalaRunTime.isTuple
+import scala.reflect.reify.codegen._
+
+trait Reify extends Symbols
+ with Types
+ with Names
+ with Trees
+ with Positions
+ with Util {
+
+ self: Reifier =>
+
+ import mirror._
+ import definitions._
+ import treeInfo._
+
+ /**
+ * Reifies any supported value.
+ * For internal use only, use ``reified'' instead.
+ */
+ def reify(reifee: Any): Tree = reifee match {
+ // before adding some case here, in global scope, please, consider
+ // whether it can be localized like reifyAnnotationInfo or reifyScope
+ // this will help reification stay as sane as possible
+ case sym: Symbol => reifySymRef(sym)
+ case tpe: Type => reifyType(tpe)
+ case name: Name => reifyName(name)
+ case tree: Tree => reifyTree(tree)
+ case pos: Position => reifyPosition(pos)
+ case mods: mirror.Modifiers => reifyModifiers(mods)
+ case xs: List[_] => reifyList(xs)
+ case s: String => Literal(Constant(s))
+ case v if isAnyVal(v) => Literal(Constant(v))
+ case null => Literal(Constant(null))
+ case _ =>
+ throw new Error("reifee %s of type %s is not supported".format(reifee, reifee.getClass))
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/phases/Reshape.scala b/src/compiler/scala/reflect/reify/phases/Reshape.scala
new file mode 100644
index 0000000000..e700604612
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/phases/Reshape.scala
@@ -0,0 +1,296 @@
+package scala.reflect.reify
+package phases
+
+import scala.tools.nsc.symtab.Flags._
+
+trait Reshape {
+ self: Reifier =>
+
+ import mirror._
+ import definitions._
+ import treeInfo._
+
+ /**
+ * Rolls back certain changes that were introduced during typechecking of the reifee.
+ *
+ * These include:
+ * * Replacing type trees with TypeTree(tpe)
+ * * Transforming Modifiers.annotations into Symbol.annotations
+ * * Transforming Annotated annotations into AnnotatedType annotations
+ * * Transforming Annotated(annot, expr) into Typed(expr, TypeTree(Annotated(annot, _))
+ * * Non-idempotencies of the typechecker: https://issues.scala-lang.org/browse/SI-5464
+ */
+ val reshape = new Transformer {
+ var currentSymbol: Symbol = NoSymbol
+
+ override def transform(tree: Tree) = {
+ currentSymbol = tree.symbol
+
+ val preTyper = tree match {
+ case tree if tree.isErroneous =>
+ tree
+ case tt @ TypeTree() =>
+ toPreTyperTypeTree(tt)
+ case toa @ TypedOrAnnotated(_) =>
+ toPreTyperTypedOrAnnotated(toa)
+ case ta @ TypeApply(hk, ts) =>
+ val discard = ts collect { case tt: TypeTree => tt } exists isDiscarded
+ if (reifyDebug && discard) println("discarding TypeApply: " + tree)
+ if (discard) hk else ta
+ case classDef @ ClassDef(mods, name, params, impl) =>
+ val Template(parents, self, body) = impl
+ var body1 = trimAccessors(classDef, body)
+ body1 = trimSyntheticCaseClassMembers(classDef, body1)
+ var impl1 = Template(parents, self, body1).copyAttrs(impl)
+ ClassDef(mods, name, params, impl1).copyAttrs(classDef)
+ case moduledef @ ModuleDef(mods, name, impl) =>
+ val Template(parents, self, body) = impl
+ var body1 = trimAccessors(moduledef, body)
+ body1 = trimSyntheticCaseClassMembers(moduledef, body1)
+ var impl1 = Template(parents, self, body1).copyAttrs(impl)
+ ModuleDef(mods, name, impl1).copyAttrs(moduledef)
+ case template @ Template(parents, self, body) =>
+ val discardedParents = parents collect { case tt: TypeTree => tt } filter isDiscarded
+ if (reifyDebug && discardedParents.length > 0) println("discarding parents in Template: " + discardedParents.mkString(", "))
+ val parents1 = parents diff discardedParents
+ val body1 = trimSyntheticCaseClassCompanions(body)
+ Template(parents1, self, body1).copyAttrs(template)
+ case block @ Block(stats, expr) =>
+ val stats1 = trimSyntheticCaseClassCompanions(stats)
+ Block(stats1, expr).copyAttrs(block)
+ case valdef @ ValDef(mods, name, tpt, rhs) if valdef.symbol.isLazy =>
+ if (reifyDebug) println("dropping $lzy in lazy val's name: " + tree)
+ val name1 = if (name endsWith nme.LAZY_LOCAL) name dropRight nme.LAZY_LOCAL.length else name
+ ValDef(mods, name1, tpt, rhs).copyAttrs(valdef)
+ case unapply @ UnApply(fun, args) =>
+ def extractExtractor(tree: Tree): Tree = {
+ val Apply(fun, args) = tree
+ args match {
+ case List(Ident(special)) if special == nme.SELECTOR_DUMMY =>
+ val Select(extractor, flavor) = fun
+ assert(flavor == nme.unapply || flavor == nme.unapplySeq)
+ extractor
+ case _ =>
+ extractExtractor(fun)
+ }
+ }
+
+ if (reifyDebug) println("unapplying unapply: " + tree)
+ val fun1 = extractExtractor(fun)
+ Apply(fun1, args).copyAttrs(unapply)
+ case Literal(const @ Constant(tpe: Type)) =>
+ // todo. implement this
+ ???
+ case Literal(const @ Constant(sym: Symbol)) =>
+ // todo. implement this
+ ???
+ case _ =>
+ tree
+ }
+
+ super.transform(preTyper)
+ }
+
+ override def transformModifiers(mods: Modifiers) = {
+ val mods1 = toPreTyperModifiers(mods, currentSymbol)
+ super.transformModifiers(mods1)
+ }
+
+ private def toPreTyperModifiers(mods: Modifiers, sym: Symbol) = {
+ if (!sym.annotations.isEmpty) {
+ val Modifiers(flags, privateWithin, annotations) = mods
+ val postTyper = sym.annotations filter (_.original != EmptyTree)
+ if (reifyDebug && !postTyper.isEmpty) println("reify symbol annotations for: " + sym)
+ if (reifyDebug && !postTyper.isEmpty) println("originals are: " + sym.annotations)
+ val preTyper = postTyper map toPreTyperAnnotation
+ mods.withAnnotations(preTyper)
+ } else {
+ mods
+ }
+ }
+
+ /** Restore pre-typer representation of a type.
+ *
+ * NB: This is the trickiest part of reification!
+ *
+ * In most cases, we're perfectly fine to reify a Type itself (see ``reifyType'').
+ * However if the type involves a symbol declared inside the quasiquote (i.e. registered in ``boundSyms''),
+ * then we cannot reify it, or otherwise subsequent reflective compilation will fail.
+ *
+ * Why will it fail? Because reified deftrees (e.g. ClassDef(...)) will generate fresh symbols during that compilation,
+ * so naively reified symbols will become out of sync, which brings really funny compilation errors and/or crashes, e.g.:
+ * https://issues.scala-lang.org/browse/SI-5230
+ *
+ * To deal with this unpleasant fact, we need to fall back from types to equivalent trees (after all, parser trees don't contain any types, just trees, so it should be possible).
+ * Luckily, these original trees get preserved for us in the ``original'' field when Trees get transformed into TypeTrees.
+ * And if an original of a type tree is empty, we can safely assume that this type is non-essential (e.g. was inferred/generated by the compiler).
+ * In that case the type can be omitted (e.g. reified as an empty TypeTree), since it will be inferred again later on.
+ *
+ * An important property of the original is that it isn't just a pre-typer tree.
+ * It's actually kind of a post-typer tree with symbols assigned to its Idents (e.g. Ident("List") will contain a symbol that points to immutable.this.List).
+ * This is very important, since subsequent reflective compilation won't have to resolve these symbols.
+ * In general case, such resolution cannot be performed, since reification doesn't preserve lexical context,
+ * which means that reflective compilation won't be aware of, say, imports that were provided when the reifee has been compiled.
+ *
+ * This workaround worked surprisingly well and allowed me to fix several important reification bugs, until the abstraction has leaked.
+ * Suddenly I found out that in certain contexts original trees do not contain symbols, but are just parser trees.
+ * To the moment I know only one such situation: typedAnnotations does not typecheck the annotation in-place, but rather creates new trees and typechecks them, so the original remains symless.
+ * Thus we apply a workaround for that in typedAnnotated. I hope this will be the only workaround in this department.
+ *
+ * upd. Recently I went ahead and started using original for all TypeTrees, regardless of whether they refer to local symbols or not.
+ * As a result, ``reifyType'' is never called directly by tree reification (and, wow, it seems to work great!).
+ * The only usage of ``reifyType'' now is for servicing typetags, however, I have some ideas how to get rid of that as well.
+ */
+ private def isDiscarded(tt: TypeTree) = tt.original == null
+ private def toPreTyperTypeTree(tt: TypeTree): Tree = {
+ if (tt.original != null) {
+ // here we rely on the fact that the originals that reach this point
+ // have all necessary symbols attached to them (i.e. that they can be recompiled in any lexical context)
+ // if this assumption fails, please, don't be quick to add postprocessing here (like I did before)
+ // but rather try to fix this in Typer, so that it produces quality originals (like it's done for typedAnnotated)
+ if (reifyDebug) println("TypeTree, essential: %s (%s)".format(tt.tpe, tt.tpe.kind))
+ if (reifyDebug) println("verdict: rolled back to original %s".format(tt.original))
+ transform(tt.original)
+ } else {
+ // type is deemed to be non-essential
+ // erase it and hope that subsequent reflective compilation will be able to recreate it again
+ if (reifyDebug) println("TypeTree, non-essential: %s (%s)".format(tt.tpe, tt.tpe.kind))
+ if (reifyDebug) println("verdict: discarded")
+ TypeTree()
+ }
+ }
+
+ private def toPreTyperTypedOrAnnotated(tree: Tree): Tree = tree match {
+ case ty @ Typed(expr1, tt @ TypeTree()) =>
+ if (reifyDebug) println("reify typed: " + tree)
+ val annotatedArg = {
+ def loop(tree: Tree): Tree = tree match {
+ case annotated1 @ Annotated(ann, annotated2 @ Annotated(_, _)) => loop(annotated2)
+ case annotated1 @ Annotated(ann, arg) => arg
+ case _ => EmptyTree
+ }
+
+ loop(tt.original)
+ }
+ if (annotatedArg != EmptyTree) {
+ if (annotatedArg.isType) {
+ if (reifyDebug) println("verdict: was an annotated type, reify as usual")
+ ty
+ } else {
+ if (reifyDebug) println("verdict: was an annotated value, equivalent is " + tt.original)
+ toPreTyperTypedOrAnnotated(tt.original)
+ }
+ } else {
+ if (reifyDebug) println("verdict: wasn't annotated, reify as usual")
+ ty
+ }
+ case at @ Annotated(annot, arg) =>
+ if (reifyDebug) println("reify type annotations for: " + tree)
+ assert(at.tpe.isInstanceOf[AnnotatedType], "%s (%s)".format(at.tpe, at.tpe.kind))
+ val annot1 = toPreTyperAnnotation(at.tpe.asInstanceOf[AnnotatedType].annotations(0))
+ if (reifyDebug) println("originals are: " + annot1)
+ Annotated(annot1, arg).copyAttrs(at)
+ }
+
+ /** Restore pre-typer representation of an annotation.
+ * The trick here is to retain the symbols that have been populated during typechecking of the annotation.
+ * If we do not do that, subsequent reflective compilation will fail.
+ */
+ private def toPreTyperAnnotation(ann: AnnotationInfo): Tree = {
+ val args = if (ann.assocs.isEmpty) {
+ ann.args
+ } else {
+ def toScalaAnnotation(jann: ClassfileAnnotArg): Tree = jann match {
+ case LiteralAnnotArg(const) =>
+ Literal(const)
+ case ArrayAnnotArg(arr) =>
+ Apply(Ident(definitions.ArrayModule), arr.toList map toScalaAnnotation)
+ case NestedAnnotArg(ann) =>
+ toPreTyperAnnotation(ann)
+ }
+
+ ann.assocs map { case (nme, arg) => AssignOrNamedArg(Ident(nme), toScalaAnnotation(arg)) }
+ }
+
+ def extractOriginal: PartialFunction[Tree, Tree] = { case Apply(Select(New(tpt), _), _) => tpt }
+ assert(extractOriginal.isDefinedAt(ann.original), showRaw(ann.original))
+ New(TypeTree(ann.atp) setOriginal extractOriginal(ann.original), List(args))
+ }
+
+ // [Eugene] is this implemented correctly?
+ private def trimAccessors(deff: Tree, stats: List[Tree]): List[Tree] = {
+ val symdefs = stats collect { case vodef: ValOrDefDef => vodef } map (vodeff => vodeff.symbol -> vodeff) toMap
+ val accessors = collection.mutable.Map[ValDef, List[DefDef]]()
+ stats collect { case ddef: DefDef => ddef } foreach (defdef => {
+ val valdef = symdefs get defdef.symbol.accessedOrSelf collect { case vdef: ValDef => vdef } getOrElse null
+ if (valdef != null) accessors(valdef) = accessors.getOrElse(valdef, Nil) :+ defdef
+
+ def detectBeanAccessors(prefix: String): Unit = {
+ if (defdef.name.startsWith(prefix)) {
+ var name = defdef.name.toString.substring(prefix.length)
+ def uncapitalize(s: String) = if (s.length == 0) "" else { val chars = s.toCharArray; chars(0) = chars(0).toLower; new String(chars) }
+ def findValDef(name: String) = symdefs.values collect { case vdef: ValDef if nme.dropLocalSuffix(vdef.name).toString == name => vdef } headOption;
+ val valdef = findValDef(name) orElse findValDef(uncapitalize(name)) orNull;
+ if (valdef != null) accessors(valdef) = accessors.getOrElse(valdef, Nil) :+ defdef
+ }
+ }
+ detectBeanAccessors("get")
+ detectBeanAccessors("set")
+ detectBeanAccessors("is")
+ });
+
+ var stats1 = stats flatMap {
+ case vdef @ ValDef(mods, name, tpt, rhs) =>
+ val mods1 = if (accessors.contains(vdef)) {
+ val ddef = accessors(vdef)(0) // any accessor will do
+ val Modifiers(flags, privateWithin, annotations) = mods
+ var flags1 = flags & ~LOCAL
+ if (!ddef.symbol.isPrivate) flags1 = flags1 & ~PRIVATE
+ val privateWithin1 = ddef.mods.privateWithin
+ val annotations1 = accessors(vdef).foldLeft(annotations)((curr, acc) => curr ++ (acc.symbol.annotations map toPreTyperAnnotation))
+ Modifiers(flags1, privateWithin1, annotations1) setPositions mods.positions
+ } else {
+ mods
+ }
+ val mods2 = toPreTyperModifiers(mods1, vdef.symbol)
+ val name1 = nme.dropLocalSuffix(name)
+ val vdef1 = ValDef(mods2, name1, tpt, rhs)
+ if (reifyDebug) println("resetting visibility of field: %s => %s".format(vdef, vdef1))
+ Some(vdef1) // no copyAttrs here, because new ValDef and old symbols are not out of sync
+ case ddef @ DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ if (accessors.values.exists(_.contains(ddef))) {
+ if (reifyDebug) println("discarding accessor method: " + ddef)
+ None
+ } else {
+ Some(ddef)
+ }
+ case tree =>
+ Some(tree)
+ }
+
+ stats1
+ }
+
+ private def trimSyntheticCaseClassMembers(deff: Tree, stats: List[Tree]): List[Tree] =
+ stats filterNot (memberDef => memberDef.isDef && {
+ val isSynthetic = memberDef.symbol.isSynthetic
+ // this doesn't work for local classes, e.g. for ones that are top-level to a quasiquote (see comments to companionClass)
+ // that's why I replace the check with an assumption that all synthetic members are, in fact, generated of case classes
+ // val isCaseMember = deff.symbol.isCaseClass || deff.symbol.companionClass.isCaseClass
+ val isCaseMember = true
+ if (isSynthetic && isCaseMember && reifyDebug) println("discarding case class synthetic def: " + memberDef)
+ isSynthetic && isCaseMember
+ })
+
+ private def trimSyntheticCaseClassCompanions(stats: List[Tree]): List[Tree] =
+ stats diff (stats collect { case moddef: ModuleDef => moddef } filter (moddef => {
+ val isSynthetic = moddef.symbol.isSynthetic
+ // this doesn't work for local classes, e.g. for ones that are top-level to a quasiquote (see comments to companionClass)
+ // that's why I replace the check with an assumption that all synthetic modules are, in fact, companions of case classes
+ // val isCaseCompanion = moddef.symbol.companionClass.isCaseClass
+ val isCaseCompanion = true
+ if (isSynthetic && isCaseCompanion && reifyDebug) println("discarding synthetic case class companion: " + moddef)
+ isSynthetic && isCaseCompanion
+ }))
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/runtime/ClassLoaders.scala b/src/compiler/scala/reflect/runtime/ClassLoaders.scala
new file mode 100644
index 0000000000..b73d57c04d
--- /dev/null
+++ b/src/compiler/scala/reflect/runtime/ClassLoaders.scala
@@ -0,0 +1,25 @@
+package scala.reflect
+package runtime
+
+trait ClassLoaders extends internal.SymbolTable { self: SymbolTable =>
+
+ def staticClass(fullname: String) =
+ definitions.getRequiredClass(fullname)
+
+ def staticModule(fullname: String) =
+ definitions.getRequiredModule(fullname)
+
+ /** 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.
+ */
+ override def missingHook(owner: Symbol, name: Name): Symbol =
+ if (owner.isRoot && isJavaClass(name.toString))
+ definitions.EmptyPackageClass.info decl name
+ else if (name.isTermName && owner.hasPackageFlag && !owner.isEmptyPackageClass)
+ makeScalaPackage(if (owner.isRoot) name.toString else owner.fullName+"."+name).sourceModule
+ else {
+ info("*** missing: "+name+"/"+name.isTermName+"/"+owner+"/"+owner.hasPackageFlag+"/"+owner.info.decls.getClass)
+ super.missingHook(owner, name)
+ }
+}
diff --git a/src/compiler/scala/reflect/runtime/ConversionUtil.scala b/src/compiler/scala/reflect/runtime/ConversionUtil.scala
index 8c32026e37..e45fc243c6 100644
--- a/src/compiler/scala/reflect/runtime/ConversionUtil.scala
+++ b/src/compiler/scala/reflect/runtime/ConversionUtil.scala
@@ -12,6 +12,7 @@ trait ConversionUtil { self: SymbolTable =>
/** A cache that maintains a bijection between Java reflection type `J`
* and Scala reflection type `S`.
*/
+ // todo. should be weak
protected class TwoWayCache[J, S] {
private val toScalaMap = new HashMap[J, S]
diff --git a/src/compiler/scala/reflect/runtime/JavaToScala.scala b/src/compiler/scala/reflect/runtime/JavaToScala.scala
index 89fd6bab64..6688d77985 100644
--- a/src/compiler/scala/reflect/runtime/JavaToScala.scala
+++ b/src/compiler/scala/reflect/runtime/JavaToScala.scala
@@ -34,16 +34,42 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
val global: JavaToScala.this.type = self
}
- protected def defaultReflectiveClassLoader(): JClassLoader = {
- val cl = Thread.currentThread.getContextClassLoader
- if (cl == null) getClass.getClassLoader else cl
- }
+ /** Defines the classloader that will be used for all class resolution activities in this mirror.
+ * Is mutable, since sometimes we need to change it in flight (e.g. to make the default mirror work with REPL).
+ *
+ * If you want to have a mirror with non-standard class resolution, override this var
+ * (or, even simpler, use the `mkMirror` function from `scala.reflect` package)
+ *
+ * Be careful, though, since fancy stuff might happen.
+ * Here's one example:
+ *
+ * partest uses a URLClassLoader(urls, null) with custom classpath to run workers (in separate threads)
+ * however it doesn't set the context classloader for them, so they inherit the system classloader
+ * http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html
+ *
+ * Once upon a time, scala.reflect.mirror was loaded using getClass.getClassLoader,
+ * which also means that classOf[...] constructs such as:
+ *
+ * classOf[scala.reflect.ScalaSignature]
+ *
+ * in unpickleClass were also loaded by the URLClassLoader
+ *
+ * But mirror's classLoader used Thread.currentThread.getContextClassLoader,
+ * which introduced a subtle bug that made the following snippet incorrectly:
+ *
+ * jclazz.getAnnotation(classOf[scala.reflect.ScalaSignature])
+ *
+ * Indeed, jclazz was loaded by context classloader, which defaulted to system classloader,
+ * while ScalaSignature class was loaded by getClass.getClassLoader, which was incompatible with system classloader.
+ * As a result, unpickler couldn't see the signature and that blew up the mirror.
+ */
+ var classLoader: ClassLoader
/** Paul: It seems the default class loader does not pick up root classes, whereas the system classloader does.
* Can you check with your newly acquired classloader fu whether this implementation makes sense?
*/
def javaClass(path: String): jClass[_] =
- javaClass(path, defaultReflectiveClassLoader())
+ javaClass(path, classLoader)
def javaClass(path: String, classLoader: JClassLoader): jClass[_] =
Class.forName(path, true, classLoader)
@@ -75,19 +101,70 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
(if (msg eq null) "reflection error while loading " + clazz.name
else "error while loading " + clazz.name) + ", " + msg)
}
- try {
- markAbsent(NoType)
- val ssig = jclazz.getAnnotation(classOf[scala.reflect.ScalaSignature])
+ // don't use classOf[scala.reflect.ScalaSignature] here, because it will use getClass.getClassLoader, not mirror's classLoader
+ // don't use asInstanceOf either because of the same reason (lol, I cannot believe I fell for it)
+ // don't use structural types to simplify reflective invocations because of the same reason
+ // todo. test for this
+ def loadAnnotation(name: String): java.lang.annotation.Annotation = {
+ def inferClasspath(cl: ClassLoader) = cl match {
+ case cl: java.net.URLClassLoader => "[" + (cl.getURLs mkString ",") + "]"
+ case _ => "<unknown>"
+ }
+ def show(cl: ClassLoader) = cl match {
+ case cl if cl != null =>
+ "%s of type %s with classpath %s".format(cl, cl.getClass, inferClasspath(cl))
+ case null =>
+ import scala.tools.util.PathResolver.Environment._
+ "primordial classloader with boot classpath [%s]".format(javaBootClassPath)
+ }
+
+ try {
+ val cls_ann = Class.forName(name, true, classLoader)
+ val anns = jclazz.getAnnotations
+ val ann = anns find (_.annotationType == cls_ann) orNull;
+ if (ann == null && anns.find(_.annotationType.getName == name).isDefined) {
+ val msg = "Mirror classloader mismatch: %s (loaded by %s)%nis unrelated to the mirror's classloader (%s)"
+ throw new Error(msg.format(jclazz, show(jclazz.getClassLoader), show(classLoader)))
+ }
+ ann
+ } catch {
+ case ex: ClassNotFoundException =>
+ val msg = "Dysfunctional mirror classloader, cannot load %s: %s."
+ throw new Error(msg.format(name, show(classLoader)), ex)
+ }
+ }
+ def loadScalaSignature: Option[String] = {
+ val ssig = loadAnnotation("scala.reflect.ScalaSignature")
if (ssig != null) {
- info("unpickling Scala "+clazz + " and " + module+ ", owner = " + clazz.owner)
- val bytes = ssig.bytes.getBytes
- val len = ByteCodecs.decode(bytes)
- unpickler.unpickle(bytes take len, 0, clazz, module, jclazz.getName)
+ val bytesMethod = ssig.annotationType.getMethod("bytes")
+ val result = bytesMethod.invoke(ssig)
+ Some(result.asInstanceOf[String])
} else {
- val slsig = jclazz.getAnnotation(classOf[scala.reflect.ScalaLongSignature])
- if (slsig != null) {
+ None
+ }
+ }
+ def loadScalaLongSignature: Option[Array[String]] = {
+ val slsig = loadAnnotation("scala.reflect.ScalaLongSignature")
+ if (slsig != null) {
+ val bytesMethod = slsig.annotationType.getMethod("bytes")
+ val result = bytesMethod.invoke(slsig)
+ Some(result.asInstanceOf[Array[String]])
+ } else {
+ None
+ }
+ }
+ try {
+ markAbsent(NoType)
+ val sigs = (loadScalaSignature, loadScalaLongSignature)
+ sigs match {
+ case (Some(ssig), _) =>
+ info("unpickling Scala "+clazz + " and " + module+ ", owner = " + clazz.owner)
+ val bytes = ssig.getBytes
+ val len = ByteCodecs.decode(bytes)
+ unpickler.unpickle(bytes take len, 0, clazz, module, jclazz.getName)
+ case (_, Some(slsig)) =>
info("unpickling Scala "+clazz + " and " + module + " with long Scala signature")
- val byteSegments = slsig.bytes map (_.getBytes)
+ val byteSegments = slsig map (_.getBytes)
val lens = byteSegments map ByteCodecs.decode
val bytes = Array.ofDim[Byte](lens.sum)
var len = 0
@@ -96,10 +173,10 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
len += l
}
unpickler.unpickle(bytes, 0, clazz, module, jclazz.getName)
- } else { // class does not have a Scala signature; it's a Java class
+ case (None, None) =>
+ // class does not have a Scala signature; it's a Java class
info("translating reflection info for Java " + jclazz) //debug
initClassModule(clazz, module, new FromJavaClassCompleter(clazz, module, jclazz))
- }
}
} catch {
case ex: MissingRequirementError =>
@@ -383,52 +460,70 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
*/
def classToScala(jclazz: jClass[_]): Symbol = classCache.toScala(jclazz) {
val jname = javaTypeName(jclazz)
- val owner = sOwner(jclazz)
- val simpleName = scalaSimpleName(jclazz)
-
- val sym = {
- def lookup = {
- def coreLookup(name: Name): Symbol = {
- val sym = owner.info.decl(name)
- sym orElse {
- if (name.startsWith(nme.NAME_JOIN_STRING))
- coreLookup(name.subName(1, name.length))
- else
- NoSymbol
+
+ val sym =
+ if (jname == fulltpnme.RuntimeNothing)
+ NothingClass
+ else if (jname == fulltpnme.RuntimeNull)
+ NullClass
+ else
+ {
+ val owner = sOwner(jclazz)
+ val simpleName = scalaSimpleName(jclazz)
+
+ def lookup = {
+ def coreLookup(name: Name): Symbol = {
+ val sym = owner.info.decl(name)
+ sym orElse {
+ if (name.startsWith(nme.NAME_JOIN_STRING))
+ coreLookup(name.subName(1, name.length))
+ else
+ NoSymbol
+ }
+ }
+
+ if (nme.isModuleName(simpleName)) {
+ val moduleName = nme.stripModuleSuffix(simpleName).toTermName
+ val sym = coreLookup(moduleName)
+ if (sym == NoSymbol) sym else sym.moduleClass
+ } else {
+ coreLookup(simpleName)
}
}
- if (nme.isModuleName(simpleName)) {
- val moduleName = nme.stripModuleSuffix(simpleName).toTermName
- val sym = coreLookup(moduleName)
- if (sym == NoSymbol) sym else sym.moduleClass
- } else {
- coreLookup(simpleName)
+ val sym = {
+ if (jclazz.isMemberClass && !nme.isImplClassName(jname)) {
+ lookup
+ } else if (jclazz.isLocalClass || invalidClassName(jname)) {
+ // local classes and implementation classes not preserved by unpickling - treat as Java
+ jclassAsScala(jclazz)
+ } else if (jclazz.isArray) {
+ ArrayClass
+ } else javaTypeToValueClass(jclazz) orElse {
+ // jclazz is top-level - get signature
+ lookup
+ // val (clazz, module) = createClassModule(
+ // sOwner(jclazz), newTypeName(jclazz.getSimpleName), new TopClassCompleter(_, _))
+ // classCache enter (jclazz, clazz)
+ // clazz
+ }
}
- }
- if (jclazz.isMemberClass && !nme.isImplClassName(jname)) {
- lookup
- } else if (jclazz.isLocalClass || invalidClassName(jname)) {
- // local classes and implementation classes not preserved by unpickling - treat as Java
- jclassAsScala(jclazz)
- } else if (jclazz.isArray) {
- ArrayClass
- } else javaTypeToValueClass(jclazz) orElse {
- // jclazz is top-level - get signature
- lookup
- // val (clazz, module) = createClassModule(
- // sOwner(jclazz), newTypeName(jclazz.getSimpleName), new TopClassCompleter(_, _))
- // classCache enter (jclazz, clazz)
- // clazz
- }
- }
+ if (!sym.isType) {
+ val classloader = jclazz.getClassLoader
+ println("classloader is: %s of type %s".format(classloader, classloader.getClass))
+ def inferClasspath(cl: ClassLoader) = cl match {
+ case cl: java.net.URLClassLoader => "[" + (cl.getURLs mkString ",") + "]"
+ case _ => "<unknown>"
+ }
+ println("classpath is: %s".format(inferClasspath(classloader)))
+ def msgNoSym = "no symbol could be loaded from %s (scala equivalent is %s) by name %s".format(owner, jclazz, simpleName)
+ def msgIsNotType = "not a type: symbol %s loaded from %s (scala equivalent is %s) by name %s".format(sym, owner, jclazz, simpleName)
+ assert(false, if (sym == NoSymbol) msgNoSym else msgIsNotType)
+ }
- if (!sym.isType) {
- def msgNoSym = "no symbol could be loaded from %s (scala equivalent is %s) by name %s".format(owner, jclazz, simpleName)
- def msgIsNotType = "not a type: symbol %s loaded from %s (scala equivalent is %s) by name %s".format(sym, owner, jclazz, simpleName)
- assert(false, if (sym == NoSymbol) msgNoSym else msgIsNotType)
- }
+ sym
+ }
sym.asInstanceOf[ClassSymbol]
}
diff --git a/src/compiler/scala/reflect/runtime/Memoizer.scala b/src/compiler/scala/reflect/runtime/Memoizer.scala
deleted file mode 100644
index 4c1b82ae6d..0000000000
--- a/src/compiler/scala/reflect/runtime/Memoizer.scala
+++ /dev/null
@@ -1,15 +0,0 @@
-package scala.reflect.runtime
-
-import collection.mutable.ArrayBuffer
-import Mirror.Type
-
-/** Class that can be used for memoizing types in reified trees */
-class Memoizer {
- private val mem = new ArrayBuffer[Mirror.Type]
- def get(n: Int): Type = mem(n)
- def add(n: Int, tpe: Type): Type = {
- while (mem.length <= n) mem += null
- mem(n) = tpe
- tpe
- }
-}
diff --git a/src/compiler/scala/reflect/runtime/Mirror.scala b/src/compiler/scala/reflect/runtime/Mirror.scala
index d3e4dd7619..20024ed058 100644
--- a/src/compiler/scala/reflect/runtime/Mirror.scala
+++ b/src/compiler/scala/reflect/runtime/Mirror.scala
@@ -1,24 +1,24 @@
package scala.reflect
package runtime
-import internal.{SomePhase, NoPhase, Phase, TreeGen}
import java.lang.reflect.Array
+import ReflectionUtils._
+import scala.tools.nsc.util.ScalaClassLoader._
/** The mirror for standard runtime reflection from Java.
*/
-class Mirror extends Universe with RuntimeTypes with TreeBuildUtil with ToolBoxes with api.Mirror {
+class Mirror(var classLoader: ClassLoader) extends Universe with api.Mirror {
definitions.init()
-
import definitions._
def symbolForName(name: String): Symbol = {
- val clazz = javaClass(name, defaultReflectiveClassLoader())
+ val clazz = javaClass(name, classLoader)
classToScala(clazz)
}
def companionInstance(clazz: Symbol): AnyRef = {
- val singleton = ReflectionUtils.singletonInstance(clazz.fullName, defaultReflectiveClassLoader())
+ val singleton = singletonInstance(classLoader, clazz.fullName)
singleton
}
@@ -46,17 +46,31 @@ class Mirror extends Universe with RuntimeTypes with TreeBuildUtil with ToolBoxe
jmeth.invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*)
}
- override def classToType(jclazz: java.lang.Class[_]): Type = typeToScala(jclazz)
- override def classToSymbol(jclazz: java.lang.Class[_]): Symbol = classToScala(jclazz)
+ private def validateIncomingClassLoader(wannabeCl: ClassLoader) = {
+ val ourCls = loaderChain(classLoader)
+ if (wannabeCl != null && !(ourCls contains wannabeCl))
+ throw new Error("class doesn't belong to the classloader chain of the mirror")
+ }
+
+ def classToType(jclazz: java.lang.Class[_]): Type = {
+ validateIncomingClassLoader(jclazz.getClassLoader)
+ typeToScala(jclazz)
+ }
+
+ def classToSymbol(jclazz: java.lang.Class[_]): Symbol = {
+ validateIncomingClassLoader(jclazz.getClassLoader)
+ classToScala(jclazz)
+ }
+
+ def typeToClass(tpe: Type): java.lang.Class[_] =
+ typeToJavaClass(tpe)
- override def typeToClass(tpe: Type): java.lang.Class[_] = typeToJavaClass(tpe)
- override def symbolToClass(sym: Symbol): java.lang.Class[_] = classToJava(sym)
+ def symbolToClass(sym: Symbol): java.lang.Class[_] =
+ classToJava(sym)
override def inReflexiveMirror = true
}
-object Mirror extends Mirror
-
/** test code; should go to tests once things settle down a bit
*
diff --git a/src/compiler/scala/reflect/runtime/RuntimeTypes.scala b/src/compiler/scala/reflect/runtime/RuntimeTypes.scala
deleted file mode 100644
index 84d02ab7a0..0000000000
--- a/src/compiler/scala/reflect/runtime/RuntimeTypes.scala
+++ /dev/null
@@ -1,27 +0,0 @@
-package scala.reflect
-package runtime
-
-import collection.mutable.ListBuffer
-
-trait RuntimeTypes extends Universe with api.RuntimeTypes {
-
- /** To lift path dependent types into reflection, we use InstanceRefSymbols.
- * Two of these are equal if they point to the same object reference. Todo: remove
- */
- case class InstanceRefSymbol(value: AnyRef) extends TermSymbol(NoSymbol, NoPosition, nme.EMPTY)
- object InstanceRefSymbol extends InstanceRefSymbolExtractor
-
- override private[reflect] def namedType(pre: Type, sym: Symbol, args: List[Type]): Type = {
- val tparamBuf = new ListBuffer[Symbol]
- val args1 = for (arg <- args) yield arg match {
- case _: TypeBounds =>
- val ex = pre.typeSymbol.freshExistential("$ex") setInfo arg
- tparamBuf += ex
- TypeRef(NoPrefix, ex, List())
- case _ =>
- arg
- }
- existentialAbstraction(tparamBuf.toList, typeRef(pre, sym, args1))
- }
-
-} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/runtime/Loaders.scala b/src/compiler/scala/reflect/runtime/SymbolLoaders.scala
index 4b35a5b37e..7c1cc16152 100644
--- a/src/compiler/scala/reflect/runtime/Loaders.scala
+++ b/src/compiler/scala/reflect/runtime/SymbolLoaders.scala
@@ -5,7 +5,7 @@ import internal.Flags
import java.lang.{Class => jClass, Package => jPackage}
import collection.mutable
-trait Loaders { self: SymbolTable =>
+trait SymbolLoaders { self: SymbolTable =>
/** The lazy type for root.
*/
@@ -123,6 +123,11 @@ trait Loaders { self: SymbolTable =>
}
}
+ /** Assert that packages have package scopes */
+ override def validateClassInfo(tp: ClassInfoType) {
+ assert(!tp.typeSymbol.isPackageClass || tp.decls.isInstanceOf[PackageScope])
+ }
+
override def newPackageScope(pkgClass: Symbol) = new PackageScope(pkgClass)
override def scopeTransform(owner: Symbol)(op: => Scope): Scope =
diff --git a/src/compiler/scala/reflect/runtime/SymbolTable.scala b/src/compiler/scala/reflect/runtime/SymbolTable.scala
index 5331f0a53e..64a5894d01 100644
--- a/src/compiler/scala/reflect/runtime/SymbolTable.scala
+++ b/src/compiler/scala/reflect/runtime/SymbolTable.scala
@@ -3,29 +3,10 @@ package runtime
/**
* This symbol table trait fills in the definitions so that class information is obtained by refection.
- * It can be used either from the reflexive mirror itself (class Universe), or else from
+ * It can be used either from the reflexive mirror itself (class Mirror), or else from
* a runtime compiler that uses reflection to get a class information (class scala.tools.nsc.ReflectGlobal)
*/
-trait SymbolTable extends internal.SymbolTable with JavaToScala with ScalaToJava with Loaders with SynchronizedOps {
-
- /** 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.
- */
- override def missingHook(owner: Symbol, name: Name): Symbol =
- if (owner.isRoot && isJavaClass(name.toString))
- definitions.EmptyPackageClass.info decl name
- else if (name.isTermName && owner.hasPackageFlag && !owner.isEmptyPackageClass)
- makeScalaPackage(if (owner.isRoot) name.toString else owner.fullName+"."+name).sourceModule
- else {
- info("*** missing: "+name+"/"+name.isTermName+"/"+owner+"/"+owner.hasPackageFlag+"/"+owner.info.decls.getClass)
- super.missingHook(owner, name)
- }
-
- /** Assert that packages have package scopes */
- override def validateClassInfo(tp: ClassInfoType) {
- assert(!tp.typeSymbol.isPackageClass || tp.decls.isInstanceOf[PackageScope])
- }
+trait SymbolTable extends internal.SymbolTable with JavaToScala with ScalaToJava with ClassLoaders with SymbolLoaders with SynchronizedOps {
def info(msg: => String) =
if (settings.verbose.value) println("[reflect-compiler] "+msg)
diff --git a/src/compiler/scala/reflect/runtime/SynchronizedSymbols.scala b/src/compiler/scala/reflect/runtime/SynchronizedSymbols.scala
index 3f2fa30be2..6fc5f7ed8a 100644
--- a/src/compiler/scala/reflect/runtime/SynchronizedSymbols.scala
+++ b/src/compiler/scala/reflect/runtime/SynchronizedSymbols.scala
@@ -14,19 +14,20 @@ trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable =>
override def connectModuleToClass(m: ModuleSymbol, moduleClass: ClassSymbol): ModuleSymbol =
synchronized { super.connectModuleToClass(m, moduleClass) }
- override def newFreeVar(name: TermName, tpe: Type, value: Any, newFlags: Long = 0L): FreeVar =
- new FreeVar(name, value) with SynchronizedTermSymbol initFlags newFlags setInfo tpe
+ override def newFreeTerm(name: TermName, info: Type, value: => Any, origin: String = null, newFlags: Long = 0L): FreeTerm =
+ new FreeTerm(name, value, origin) with SynchronizedTermSymbol initFlags newFlags setInfo info
- override protected def makeNoSymbol = new NoSymbol with SynchronizedSymbol
+ override def newFreeType(name: TypeName, info: Type, value: => Any, origin: String = null, newFlags: Long = 0L): FreeType =
+ new FreeType(name, value, origin) with SynchronizedTypeSymbol initFlags newFlags setInfo info
+
+ override protected def makeNoSymbol: NoSymbol = new NoSymbol with SynchronizedSymbol
trait SynchronizedSymbol extends Symbol {
- override def rawowner = synchronized { super.rawowner }
- override def rawname = synchronized { super.rawname }
override def rawflags = synchronized { super.rawflags }
+ override def rawflags_=(x: Long) = synchronized { super.rawflags_=(x) }
- override def rawflags_=(x: FlagsType) = synchronized { super.rawflags_=(x) }
- override def name_=(x: Name) = synchronized { super.name_=(x) }
+ override def rawowner = synchronized { super.rawowner }
override def owner_=(owner: Symbol) = synchronized { super.owner_=(owner) }
override def validTo = synchronized { super.validTo }
@@ -55,37 +56,55 @@ trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable =>
// ------ creators -------------------------------------------------------------------
- override def newTermSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol =
- new TermSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags
-
- override def newAbstractTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AbstractTypeSymbol =
+ override protected def createAbstractTypeSymbol(name: TypeName, pos: Position, newFlags: Long): AbstractTypeSymbol =
new AbstractTypeSymbol(this, pos, name) with SynchronizedTypeSymbol initFlags newFlags
- override def newAliasTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AliasTypeSymbol =
+ override protected def createAliasTypeSymbol(name: TypeName, pos: Position, newFlags: Long): AliasTypeSymbol =
new AliasTypeSymbol(this, pos, name) with SynchronizedTypeSymbol initFlags newFlags
- override def newModuleSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleSymbol =
- new ModuleSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags
-
- override def newMethodSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): MethodSymbol =
- new MethodSymbol(this, pos, name) with SynchronizedMethodSymbol initFlags newFlags
+ override protected def createTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position, newFlags: Long): TypeSkolem =
+ new TypeSkolem(this, pos, name, origin) with SynchronizedTypeSymbol initFlags newFlags
- override def newClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ClassSymbol =
+ override protected def createClassSymbol(name: TypeName, pos: Position, newFlags: Long): ClassSymbol =
new ClassSymbol(this, pos, name) with SynchronizedClassSymbol initFlags newFlags
- override def newModuleClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleClassSymbol =
+ override protected def createModuleClassSymbol(name: TypeName, pos: Position, newFlags: Long): ModuleClassSymbol =
new ModuleClassSymbol(this, pos, name) with SynchronizedModuleClassSymbol initFlags newFlags
- override def newTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position = NoPosition, newFlags: Long = 0L): TypeSkolem =
- if ((newFlags & DEFERRED) == 0L)
- new TypeSkolem(this, pos, name, origin) with SynchronizedTypeSymbol initFlags newFlags
- else
- new TypeSkolem(this, pos, name, origin) with AbstractTypeMixin with SynchronizedTypeSymbol initFlags newFlags
+ override protected def createPackageClassSymbol(name: TypeName, pos: Position, newFlags: Long): PackageClassSymbol =
+ new PackageClassSymbol(this, pos, name) with SynchronizedModuleClassSymbol initFlags newFlags
+
+ override protected def createRefinementClassSymbol(pos: Position, newFlags: Long): RefinementClassSymbol =
+ new RefinementClassSymbol(this, pos) with SynchronizedClassSymbol initFlags newFlags
+
+ override protected def createImplClassSymbol(name: TypeName, pos: Position, newFlags: Long): ClassSymbol =
+ new ClassSymbol(this, pos, name) with ImplClassSymbol with SynchronizedClassSymbol initFlags newFlags
+
+ override protected def createPackageObjectClassSymbol(pos: Position, newFlags: Long): PackageObjectClassSymbol =
+ new PackageObjectClassSymbol(this, pos) with SynchronizedClassSymbol initFlags newFlags
+
+ override protected def createTermSymbol(name: TermName, pos: Position, newFlags: Long): TermSymbol =
+ new TermSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags
+
+ override protected def createMethodSymbol(name: TermName, pos: Position, newFlags: Long): MethodSymbol =
+ new MethodSymbol(this, pos, name) with SynchronizedMethodSymbol initFlags newFlags
+
+ override protected def createModuleSymbol(name: TermName, pos: Position, newFlags: Long): ModuleSymbol =
+ new ModuleSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags
+
+ override protected def createPackageSymbol(name: TermName, pos: Position, newFlags: Long): PackageSymbol =
+ new PackageSymbol(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)
}
// ------- 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) }
}
@@ -95,6 +114,8 @@ trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable =>
}
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 }
}
diff --git a/src/compiler/scala/reflect/runtime/ToolBoxes.scala b/src/compiler/scala/reflect/runtime/ToolBoxes.scala
index 28f12b378f..6d832a590f 100644
--- a/src/compiler/scala/reflect/runtime/ToolBoxes.scala
+++ b/src/compiler/scala/reflect/runtime/ToolBoxes.scala
@@ -1,28 +1,30 @@
package scala.reflect
package runtime
-import scala.tools.nsc
-import scala.tools.nsc.reporters.Reporter
-import scala.tools.nsc.reporters.StoreReporter
-import scala.tools.nsc.reporters.AbstractReporter
+import scala.tools.nsc.reporters._
import scala.tools.nsc.ReflectGlobal
import scala.tools.nsc.CompilerCommand
import scala.tools.nsc.Global
import scala.tools.nsc.typechecker.Modes
import scala.tools.nsc.io.VirtualDirectory
import scala.tools.nsc.interpreter.AbstractFileClassLoader
-import reflect.{mirror => rm}
import scala.tools.nsc.util.FreshNameCreator
import scala.reflect.internal.Flags
import scala.tools.nsc.util.{NoSourceFile, NoFile}
import java.lang.{Class => jClass}
-import scala.tools.nsc.util.trace
+import scala.compat.Platform.EOL
trait ToolBoxes extends { self: Universe =>
- class ToolBox(val reporter: Reporter = new StoreReporter, val options: String = "") {
+ import self.{Reporter => ApiReporter}
+ import scala.tools.nsc.reporters.{Reporter => NscReporter}
- class ToolBoxGlobal(settings0: nsc.Settings, reporter0: nsc.reporters.Reporter) extends ReflectGlobal(settings0, reporter0) {
+ def mkToolBox(reporter: ApiReporter = mkSilentReporter(), options: String = "") = new ToolBox(reporter, options)
+
+ class ToolBox(val reporter: ApiReporter, val options: String) extends AbsToolBox {
+
+ class ToolBoxGlobal(settings: scala.tools.nsc.Settings, reporter: NscReporter)
+ extends ReflectGlobal(settings, reporter, ToolBox.this.classLoader) {
import definitions._
private val trace = scala.tools.nsc.util.trace when settings.debug.value
@@ -36,64 +38,7 @@ trait ToolBoxes extends { self: Universe =>
newTermName("__wrapper$" + wrapCount)
}
- private def moduleFileName(className: String) = className + "$"
-
- private def isFree(t: Tree) = t.isInstanceOf[Ident] && t.symbol.isInstanceOf[FreeVar]
-
- def typedTopLevelExpr(tree: Tree, pt: Type): Tree = {
- // !!! Why is this is in the empty package? If it's only to make
- // it inaccessible then please put it somewhere designed for that
- // rather than polluting the empty package with synthetics.
- trace("typing: ")(showAttributed(tree, true, true, settings.Yshowsymkinds.value))
- val ownerClass = EmptyPackageClass.newClassWithInfo(newTypeName("<expression-owner>"), List(ObjectClass.tpe), newScope)
- val owner = ownerClass.newLocalDummy(tree.pos)
- val ttree = typer.atOwner(tree, owner).typed(tree, analyzer.EXPRmode, pt)
- trace("typed: ")(showAttributed(ttree, true, true, settings.Yshowsymkinds.value))
- ttree
- }
-
- def defOwner(tree: Tree): Symbol = tree find (_.isDef) map (_.symbol) match {
- case Some(sym) if sym != null && sym != NoSymbol => sym.owner
- case _ => NoSymbol
- }
-
- def wrapInObject(expr: Tree, fvs: List[Symbol]): ModuleDef = {
- val obj = EmptyPackageClass.newModule(nextWrapperModuleName())
- val minfo = ClassInfoType(List(ObjectClass.tpe), newScope, obj.moduleClass)
- obj.moduleClass setInfo minfo
- obj setInfo obj.moduleClass.tpe
- val meth = obj.moduleClass.newMethod(newTermName(wrapperMethodName))
- def makeParam(fv: Symbol) = meth.newValueParameter(fv.name.toTermName) setInfo fv.tpe
- meth setInfo MethodType(fvs map makeParam, AnyClass.tpe)
- minfo.decls enter meth
- trace("wrapping ")(defOwner(expr) -> meth)
- val methdef = DefDef(meth, expr changeOwner (defOwner(expr) -> meth))
- val moduledef = ModuleDef(
- obj,
- Template(
- List(TypeTree(ObjectClass.tpe)),
- emptyValDef,
- NoMods,
- List(),
- List(List()),
- List(methdef),
- NoPosition))
- trace("wrapped: ")(showAttributed(moduledef, true, true, settings.Yshowsymkinds.value))
- val cleanedUp = resetLocalAttrs(moduledef)
- trace("cleaned up: ")(showAttributed(cleanedUp, true, true, settings.Yshowsymkinds.value))
- cleanedUp
- }
-
- def wrapInPackage(clazz: Tree): PackageDef =
- PackageDef(Ident(nme.EMPTY_PACKAGE_NAME), List(clazz))
-
- def wrapInCompilationUnit(tree: Tree): CompilationUnit = {
- val unit = new CompilationUnit(NoSourceFile)
- unit.body = tree
- unit
- }
-
- def compileExpr(expr: Tree, fvs: List[Symbol]): String = {
+ def verifyExpr(expr: Tree): Unit = {
// Previously toolboxes used to typecheck their inputs before compiling.
// Actually, the initial demo by Martin first typechecked the reified tree,
// then ran it, which typechecked it again, and only then launched the
@@ -104,44 +49,190 @@ trait ToolBoxes extends { self: Universe =>
// That's why we cannot allow inputs of toolboxes to be typechecked,
// at least not until the aforementioned issue is closed.
val typed = expr filter (t => t.tpe != null && t.tpe != NoType && !t.isInstanceOf[TypeTree])
- if (!typed.isEmpty) {
- throw new Error("cannot compile trees that are already typed")
+ if (!typed.isEmpty) throw new ToolBoxError(ToolBox.this, "reflective toolbox has failed: cannot operate on trees that are already typed")
+
+ val freeTypes = this.freeTypes(expr)
+ if (freeTypes.length > 0) {
+ var msg = "reflective toolbox has failed:" + EOL
+ msg += "unresolved free type variables (namely: " + (freeTypes map (ft => "%s %s".format(ft.name, ft.origin)) mkString ", ") + "). "
+ msg += "have you forgot to use TypeTag annotations for type parameters external to a reifee? "
+ msg += "if you have troubles tracking free type variables, consider using -Xlog-free-types"
+ throw new ToolBoxError(ToolBox.this, msg)
}
+ }
- val mdef = wrapInObject(expr, fvs)
- val pdef = wrapInPackage(mdef)
- val unit = wrapInCompilationUnit(pdef)
- val run = new Run
- run.compileUnits(List(unit), run.namerPhase)
- mdef.symbol.fullName
+ def typeCheckExpr(expr0: Tree, pt: Type, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree = {
+ verifyExpr(expr0)
+
+ // need to wrap the expr, because otherwise you won't be able to typecheck macros against something that contains free vars
+ // [Eugene] get rid of the copy/paste w.r.t compileExpr
+ val freeTerms = this.freeTerms(expr0)
+ val freeTermNames = collection.mutable.Map[Symbol, TermName]()
+ freeTerms foreach (ft => {
+ var name = ft.name.toString
+ val namesakes = freeTerms takeWhile (_ != ft) filter (ft2 => ft != ft2 && ft.name == ft2.name)
+ if (namesakes.length > 0) name += ("$" + (namesakes.length + 1))
+ freeTermNames += (ft -> newTermName(name + nme.MIRROR_FREE_VALUE_SUFFIX))
+ })
+ var expr = new Transformer {
+ override def transform(tree: Tree): Tree =
+ if (tree.hasSymbol && tree.symbol.isFreeTerm) {
+ tree match {
+ case Ident(_) =>
+ Ident(freeTermNames(tree.symbol))
+ case _ =>
+ throw new Error("internal error: %s (%s, %s) is not supported".format(tree, tree.productPrefix, tree.getClass))
+ }
+ } else {
+ super.transform(tree)
+ }
+ }.transform(expr0)
+ val dummies = freeTerms map (freeTerm => ValDef(NoMods, freeTermNames(freeTerm), TypeTree(freeTerm.info), Select(Ident(PredefModule), newTermName("$qmark$qmark$qmark"))))
+ expr = Block(dummies, expr)
+
+ // [Eugene] how can we implement that?
+ // !!! Why is this is in the empty package? If it's only to make
+ // it inaccessible then please put it somewhere designed for that
+ // rather than polluting the empty package with synthetics.
+ val ownerClass = EmptyPackageClass.newClassWithInfo(newTypeName("<expression-owner>"), List(ObjectClass.tpe), newScope)
+ val owner = ownerClass.newLocalDummy(expr.pos)
+ var currentTyper = typer.atOwner(expr, owner)
+ val wrapper1 = if (!withImplicitViewsDisabled) (currentTyper.context.withImplicitsEnabled[Tree] _) else (currentTyper.context.withImplicitsDisabled[Tree] _)
+ val wrapper2 = if (!withMacrosDisabled) (currentTyper.context.withMacrosEnabled[Tree] _) else (currentTyper.context.withMacrosDisabled[Tree] _)
+ def wrapper (tree: => Tree) = wrapper1(wrapper2(tree))
+
+ phase = (new Run).typerPhase // need to set a phase to something <= typerPhase, otherwise implicits in typedSelect will be disabled
+ currentTyper.context.setReportErrors() // need to manually set context mode, otherwise typer.silent will throw exceptions
+ reporter.reset()
+
+ trace("typing (implicit views = %s, macros = %s): ".format(!withImplicitViewsDisabled, !withMacrosDisabled))(showAttributed(expr, true, true, settings.Yshowsymkinds.value))
+ wrapper(currentTyper.silent(_.typed(expr, analyzer.EXPRmode, pt)) match {
+ case analyzer.SilentResultValue(result) =>
+ trace("success: ")(showAttributed(result, true, true, settings.Yshowsymkinds.value))
+ var Block(dummies, unwrapped) = result
+ var reversedFreeTermNames = freeTermNames map (_.swap)
+ // todo. also fixup singleton types
+ unwrapped = new Transformer {
+ override def transform(tree: Tree): Tree =
+ tree match {
+ case Ident(name) if reversedFreeTermNames contains name =>
+ Ident(reversedFreeTermNames(name))
+ case _ =>
+ super.transform(tree)
+ }
+ }.transform(unwrapped)
+ new TreeTypeSubstituter(dummies map (_.symbol), dummies map (dummy => SingleType(NoPrefix, reversedFreeTermNames(dummy.symbol.name)))).traverse(unwrapped)
+ unwrapped
+ case error @ analyzer.SilentTypeError(_) =>
+ trace("failed: ")(error.err.errMsg)
+ if (!silent) throw new ToolBoxError(ToolBox.this, "reflective typecheck has failed: %s".format(error.err.errMsg))
+ EmptyTree
+ })
}
- private def getMethod(jclazz: jClass[_], name: String) =
- jclazz.getDeclaredMethods.find(_.getName == name).get
+ def compileExpr(expr: Tree): (Object, java.lang.reflect.Method) = {
+ verifyExpr(expr)
+
+ def wrapExpr(expr0: Tree): Tree = {
+ def defOwner(tree: Tree): Symbol = tree find (_.isDef) map (_.symbol) match {
+ case Some(sym) if sym != null && sym != NoSymbol => sym.owner
+ case _ => NoSymbol
+ }
+
+ val freeTerms = this.freeTerms(expr0)
+ val freeTermNames = collection.mutable.Map[Symbol, TermName]()
+ freeTerms foreach (ft => {
+ var name = ft.name.toString
+ val namesakes = freeTerms takeWhile (_ != ft) filter (ft2 => ft != ft2 && ft.name == ft2.name)
+ if (namesakes.length > 0) name += ("$" + (namesakes.length + 1))
+ freeTermNames += (ft -> newTermName(name + nme.MIRROR_FREE_VALUE_SUFFIX))
+ })
+ val expr = new Transformer {
+ override def transform(tree: Tree): Tree =
+ if (tree.hasSymbol && tree.symbol.isFreeTerm) {
+ tree match {
+ case Ident(_) =>
+ Apply(Ident(freeTermNames(tree.symbol)), List())
+ case _ =>
+ throw new Error("internal error: %s (%s, %s) is not supported".format(tree, tree.productPrefix, tree.getClass))
+ }
+ } else {
+ super.transform(tree)
+ }
+ }.transform(expr0)
+
+ val obj = EmptyPackageClass.newModule(nextWrapperModuleName())
+ val minfo = ClassInfoType(List(ObjectClass.tpe), newScope, obj.moduleClass)
+ obj.moduleClass setInfo minfo
+ obj setInfo obj.moduleClass.tpe
+ val meth = obj.moduleClass.newMethod(newTermName(wrapperMethodName))
+ def makeParam(fv: Symbol) = {
+ // [Eugene] conventional way of doing this?
+ val underlying = fv.tpe.resultType
+ val tpe = appliedType(definitions.FunctionClass(0).tpe, List(underlying))
+ meth.newValueParameter(freeTermNames(fv)) setInfo tpe
+ }
+ meth setInfo MethodType(freeTerms map makeParam, AnyClass.tpe)
+ minfo.decls enter meth
+ trace("wrapping ")(defOwner(expr) -> meth)
+ val methdef = DefDef(meth, expr changeOwner (defOwner(expr) -> meth))
+ val moduledef = ModuleDef(
+ obj,
+ Template(
+ List(TypeTree(ObjectClass.tpe)),
+ emptyValDef,
+ NoMods,
+ List(),
+ List(List()),
+ List(methdef),
+ NoPosition))
+ trace("wrapped: ")(showAttributed(moduledef, true, true, settings.Yshowsymkinds.value))
+ var cleanedUp = resetLocalAttrs(moduledef)
+ trace("cleaned up: ")(showAttributed(cleanedUp, true, true, settings.Yshowsymkinds.value))
+ cleanedUp
+ }
- def runExpr(expr: Tree): Any = {
- val fvs = (expr filter isFree map (_.symbol)).distinct
+ val mdef = wrapExpr(expr)
+ val pdef = PackageDef(Ident(nme.EMPTY_PACKAGE_NAME), List(mdef))
+ val unit = new CompilationUnit(NoSourceFile)
+ unit.body = pdef
+ val run = new Run
reporter.reset()
- val className = compileExpr(expr, fvs)
+ run.compileUnits(List(unit), run.namerPhase)
if (reporter.hasErrors) {
- throw new Error("reflective compilation has failed")
+ var msg = "reflective compilation has failed: " + EOL + EOL
+ msg += ToolBox.this.reporter.infos map (_.msg) mkString EOL
+ throw new ToolBoxError(ToolBox.this, msg)
}
+ val className = mdef.symbol.fullName
if (settings.debug.value) println("generated: "+className)
+ def moduleFileName(className: String) = className + "$"
val jclazz = jClass.forName(moduleFileName(className), true, classLoader)
val jmeth = jclazz.getDeclaredMethods.find(_.getName == wrapperMethodName).get
val jfield = jclazz.getDeclaredFields.find(_.getName == NameTransformer.MODULE_INSTANCE_NAME).get
val singleton = jfield.get(null)
+ (singleton, jmeth)
+ }
+
+ def runExpr(expr: Tree, freeTypes: Map[TypeName, Type] = Map[TypeName, Type]()): Any = {
+ val freeTerms = this.freeTerms(expr) // need to calculate them here, because later on they will be erased
+ val thunks = freeTerms map (fte => () => fte.value) // need to be lazy in order not to distort evaluation order
+
// @odersky writes: Not sure we will be able to drop this. I forgot the reason why we dereference () functions,
// but there must have been one. So I propose to leave old version in comments to be resurrected if the problem resurfaces.
-// val result = jmeth.invoke(singleton, fvs map (sym => sym.asInstanceOf[FreeVar].value.asInstanceOf[AnyRef]): _*)
+ // @Eugene writes: this dates back to the days when one could only reify functions
+ // hence, blocks were translated into nullary functions, so
+ // presumably, it was useful to immediately evaluate them to get the result of a block
+// val result = jmeth.invoke(singleton, freeTerms map (sym => sym.asInstanceOf[FreeTermVar].value.asInstanceOf[AnyRef]): _*)
// if (etpe.typeSymbol != FunctionClass(0)) result
// else {
// val applyMeth = result.getClass.getMethod("apply")
// applyMeth.invoke(result)
// }
- jmeth.invoke(singleton, fvs map (sym => sym.asInstanceOf[FreeVar].value.asInstanceOf[AnyRef]): _*)
+ val (singleton, jmeth) = compileExpr(expr)
+ jmeth.invoke(singleton, thunks map (_.asInstanceOf[AnyRef]): _*)
}
def showAttributed(tree: Tree, printTypes: Boolean = true, printIds: Boolean = true, printKinds: Boolean = false): String = {
@@ -161,6 +252,7 @@ trait ToolBoxes extends { self: Universe =>
}
}
+ // todo. is not going to work with quoted arguments with embedded whitespaces
lazy val arguments = options.split(" ")
lazy val virtualDirectory =
@@ -170,49 +262,96 @@ trait ToolBoxes extends { self: Universe =>
}
lazy val compiler: ToolBoxGlobal = {
- val errorFn: String => Unit = reporter.error(scala.tools.nsc.util.NoPosition, _)
- val command = reporter match {
- case reporter: AbstractReporter => new CompilerCommand(arguments.toList, reporter.settings, errorFn)
- case _ => new CompilerCommand(arguments.toList, errorFn)
+ try {
+ val errorFn: String => Unit = msg => reporter.log(NoPosition, msg, reporter.ERROR)
+ // [Eugene] settings shouldn't be passed via reporters, this is crazy
+// val command = reporter match {
+// case reporter: AbstractReporter => new CompilerCommand(arguments.toList, reporter.settings, errorFn)
+// case _ => new CompilerCommand(arguments.toList, errorFn)
+// }
+ val command = new CompilerCommand(arguments.toList, errorFn)
+ command.settings.outputDirs setSingleOutput virtualDirectory
+ val nscReporter = new ApiToNscReporterProxy(reporter) { val settings = command.settings }
+ val instance = new ToolBoxGlobal(command.settings, nscReporter)
+ if (nscReporter.hasErrors) {
+ var msg = "reflective compilation has failed: cannot initialize the compiler: " + EOL + EOL
+ msg += reporter.infos map (_.msg) mkString EOL
+ throw new ToolBoxError(this, msg)
+ }
+ instance.phase = (new instance.Run).typerPhase // need to manually set a phase, because otherwise TypeHistory will crash
+ instance
+ } catch {
+ case ex: Throwable =>
+ var msg = "reflective compilation has failed: cannot initialize the compiler due to %s".format(ex.toString)
+ throw new ToolBoxError(this, msg, ex)
}
-
- command.settings.outputDirs setSingleOutput virtualDirectory
- val instance = new ToolBoxGlobal(command.settings, reporter)
-
- // need to establish a run an phase because otherwise we run into an assertion in TypeHistory
- // that states that the period must be different from NoPeriod
- val run = new instance.Run
- instance.phase = run.refchecksPhase
- instance
}
- lazy val importer = new compiler.Importer {
- val from: self.type = self
- }
+ // @Eugene: how do I make this work without casts?
+ // lazy val importer = compiler.mkImporter(self)
+ lazy val importer = compiler.mkImporter(self).asInstanceOf[compiler.Importer { val from: self.type }]
lazy val exporter = importer.reverse
- lazy val classLoader = new AbstractFileClassLoader(virtualDirectory, defaultReflectiveClassLoader)
+ lazy val classLoader = new AbstractFileClassLoader(virtualDirectory, self.classLoader)
- def typeCheck(tree: rm.Tree, expectedType: rm.Type): rm.Tree = {
- if (compiler.settings.verbose.value) println("typing "+tree+", pt = "+expectedType)
- val ctree: compiler.Tree = importer.importTree(tree.asInstanceOf[Tree])
- val pt: compiler.Type = importer.importType(expectedType.asInstanceOf[Type])
- val ttree: compiler.Tree = compiler.typedTopLevelExpr(ctree, pt)
- val rmttree = exporter.importTree(ttree).asInstanceOf[rm.Tree]
+ def typeCheck(tree: Tree, expectedType: Type = WildcardType, freeTypes: Map[FreeType, Type] = Map[FreeType, Type](), silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree = {
+ if (compiler.settings.verbose.value) println("typing "+tree+", expectedType = "+expectedType+", freeTypes = "+freeTypes)
+ var ctree: compiler.Tree = importer.importTree(tree)
+ var cexpectedType: compiler.Type = importer.importType(expectedType)
+
+ if (compiler.settings.verbose.value) println("substituting "+ctree+", expectedType = "+expectedType)
+ val cfreeTypes: Map[compiler.FreeType, compiler.Type] = freeTypes map { case (k, v) => (importer.importSymbol(k).asInstanceOf[compiler.FreeType], importer.importType(v)) }
+ ctree = compiler.substituteFreeTypes(ctree, cfreeTypes)
+ cexpectedType = compiler.substituteFreeTypes(cexpectedType, cfreeTypes)
+
+ if (compiler.settings.verbose.value) println("typing "+ctree+", expectedType = "+expectedType)
+ val ttree: compiler.Tree = compiler.typeCheckExpr(ctree, cexpectedType, silent = silent, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled)
+ val rmttree = exporter.importTree(ttree)
rmttree
}
- def typeCheck(tree: rm.Tree): rm.Tree =
- typeCheck(tree, WildcardType.asInstanceOf[rm.Type])
+ def inferImplicitValue(pt: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false): Tree =
+ // todo. implement this
+ ???
+
+ def inferImplicitView(tree: Tree, from: Type, to: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, reportAmbiguous: Boolean = true): Tree =
+ // todo. implement this
+ ???
+
+ def resetAllAttrs[T <: Tree](tree: T): T = {
+ val ctree: compiler.Tree = importer.importTree(tree)
+ val ttree: compiler.Tree = compiler.resetAllAttrs(ctree)
+ val rmttree = exporter.importTree(ttree)
+ rmttree.asInstanceOf[T]
+ }
+
+ def resetLocalAttrs[T <: Tree](tree: T): T = {
+ val ctree: compiler.Tree = importer.importTree(tree)
+ val ttree: compiler.Tree = compiler.resetLocalAttrs(ctree)
+ val rmttree = exporter.importTree(ttree)
+ rmttree.asInstanceOf[T]
+ }
+
+ def showAttributed(tree: Tree, printTypes: Boolean = true, printIds: Boolean = true, printKinds: Boolean = false): String =
+ compiler.showAttributed(importer.importTree(tree), printTypes, printIds, printKinds)
+
+ def runExpr(tree: Tree, freeTypes: Map[FreeType, Type] = Map[FreeType, Type]()): Any = {
+ if (compiler.settings.verbose.value) println("running "+tree+", freeTypes = "+freeTypes)
+ var ctree: compiler.Tree = importer.importTree(tree)
- def showAttributed(tree: rm.Tree, printTypes: Boolean = true, printIds: Boolean = true, printKinds: Boolean = false): String =
- compiler.showAttributed(importer.importTree(tree.asInstanceOf[Tree]), printTypes, printIds, printKinds)
+ if (compiler.settings.verbose.value) println("substituting "+ctree)
+ val cfreeTypes: Map[compiler.FreeType, compiler.Type] = freeTypes map { case (k, v) => (importer.importSymbol(k).asInstanceOf[compiler.FreeType], importer.importType(v)) }
+ ctree = compiler.substituteFreeTypes(ctree, cfreeTypes)
- def runExpr(tree: rm.Tree): Any = {
- if (compiler.settings.verbose.value) println("running "+tree)
- val ctree: compiler.Tree = importer.importTree(tree.asInstanceOf[Tree])
+ if (compiler.settings.verbose.value) println("running "+ctree)
compiler.runExpr(ctree)
}
+
+ class ToolBoxError(val toolBox: ToolBox, val message: String, val cause: Throwable = null) extends Throwable(message, cause)
+
+ object ToolBoxError extends ToolBoxErrorExtractor {
+ def unapply(error: ToolBoxError): Option[(ToolBox, String)] = Some((error.toolBox, error.message))
+ }
}
}
diff --git a/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala b/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala
deleted file mode 100644
index 61001a4778..0000000000
--- a/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala
+++ /dev/null
@@ -1,49 +0,0 @@
-package scala.reflect
-package runtime
-
-trait TreeBuildUtil extends Universe with api.TreeBuildUtil {
- /** A comment to the effect of why initialize was added to all these
- * would be appreciated. (We may as well start somewhere.)
- */
- def staticClass(fullname: String) = definitions.getRequiredClass(fullname).initialize
- def staticModule(fullname: String) = definitions.getRequiredModule(fullname).initialize
- def thisModuleType(fullname: String) = staticModule(fullname).moduleClass.initialize.thisType
-
- /** Selects type symbol with given name from the defined members of prefix type
- */
- def selectType(owner: Symbol, name: String): Symbol =
- owner.info.decl(newTypeName(name))
-
- /** Selects term symbol with given name and type from the defined members of prefix type
- * @pre The prefix type
- * @name The name of the selected member
- */
- def selectTerm(owner: Symbol, name: String): Symbol = {
- val sym = owner.info.decl(newTermName(name))
- if (sym.isOverloaded) sym suchThat (!_.isMethod)
- else sym
- }
-
- def selectOverloadedMethod(owner: Symbol, name: String, index: Int): Symbol =
- owner.info.decl(newTermName(name)).alternatives(index)
-
- def selectParam(owner: Symbol, idx: Int): Symbol = {
- def selectInList(params: List[Symbol], idx: Int, fallback: Type): Symbol = {
- if (params.isEmpty) selectIn(fallback, idx)
- else if (idx == 0) params.head
- else selectInList(params.tail, idx - 1, fallback)
- }
- def selectIn(tpe: Type, idx: Int): Symbol = tpe match {
- case PolyType(tparams, res) => selectInList(tparams, idx, res)
- case MethodType(params, res) => selectInList(params, idx, res)
- case _ => NoSymbol
- }
- selectIn(owner.info, idx)
- }
-
- def newFreeVar(name: String, info: Type, value: Any) = newFreeVar(newTermName(name), info, value)
-
- def modifiersFromInternalFlags(flags: Long, privateWithin: Name, annotations: List[Tree]): Modifiers =
- Modifiers(flags, privateWithin, annotations)
-
-} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/runtime/Universe.scala b/src/compiler/scala/reflect/runtime/Universe.scala
index 7a5dda3d8e..fd53308d0a 100644
--- a/src/compiler/scala/reflect/runtime/Universe.scala
+++ b/src/compiler/scala/reflect/runtime/Universe.scala
@@ -8,12 +8,14 @@ import internal.{SomePhase, NoPhase, Phase, TreeGen}
* It also provides methods to go from Java members to Scala members,
* using the code in JavaConversions.
*/
-class Universe extends SymbolTable {
+abstract class Universe extends SymbolTable with ToolBoxes {
type AbstractFileType = AbstractFile
def picklerPhase = SomePhase
+ type TreeGen = internal.TreeGen
+
val gen = new TreeGen { val global: Universe.this.type = Universe.this }
lazy val settings = new Settings
@@ -30,24 +32,12 @@ class Universe extends SymbolTable {
def newStrictTreeCopier: TreeCopier = new StrictTreeCopier
def newLazyTreeCopier: TreeCopier = new LazyTreeCopier
- def focusPos(pos: Position) = pos
- def isRangePos(pos: Position) = false
- def showPos(pos: Position) = "<unknown position>"
-
- type Position = String // source file?
- val NoPosition = ""
-
definitions.AnyValClass // force it.
- type TreeAnnotation = Position
- val NoTreeAnnotation: TreeAnnotation = NoPosition
- def positionToAnnotation(pos: Position): TreeAnnotation = pos // TODO
- def annotationToPosition(annot: TreeAnnotation): Position = annot //TODO
-
// establish root association to avoid cyclic dependency errors later
- classToScala(classOf[java.lang.Object]).initialize
+ // don't use classOf[...] here, because it gets serviced by getClass.getClassLoader!
+ classToScala(Class.forName("java.lang.Object", true, classLoader)).initialize
// println("initializing definitions")
definitions.init()
-
}
diff --git a/src/compiler/scala/reflect/runtime/package.scala b/src/compiler/scala/reflect/runtime/package.scala
new file mode 100644
index 0000000000..52ab2c5deb
--- /dev/null
+++ b/src/compiler/scala/reflect/runtime/package.scala
@@ -0,0 +1,5 @@
+package scala.reflect
+
+package object runtime {
+ def mkMirror(classLoader: ClassLoader): api.Mirror = new Mirror(classLoader)
+} \ No newline at end of file
diff --git a/src/compiler/scala/tools/cmd/FromString.scala b/src/compiler/scala/tools/cmd/FromString.scala
index 3792c26c34..9592e7a716 100644
--- a/src/compiler/scala/tools/cmd/FromString.scala
+++ b/src/compiler/scala/tools/cmd/FromString.scala
@@ -7,14 +7,14 @@ package scala.tools
package cmd
import nsc.io.{ Path, File, Directory }
-import scala.reflect.OptManifest
+import scala.reflect.Manifest
/** A general mechanism for defining how a command line argument
* (always a String) is transformed into an arbitrary type. A few
* example instances are in the companion object, but in general
* either IntFromString will suffice or you'll want custom transformers.
*/
-abstract class FromString[+T](implicit m: OptManifest[T]) extends PartialFunction[String, T] {
+abstract class FromString[+T](implicit m: Manifest[T]) extends PartialFunction[String, T] {
def apply(s: String): T
def isDefinedAt(s: String): Boolean = true
def zero: T = apply("")
diff --git a/src/compiler/scala/tools/nsc/ClassLoaders.scala b/src/compiler/scala/tools/nsc/ClassLoaders.scala
new file mode 100644
index 0000000000..4058ee9324
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ClassLoaders.scala
@@ -0,0 +1,64 @@
+package scala.tools.nsc
+
+import util.ScalaClassLoader
+
+trait ClassLoaders { self: Global =>
+
+ def staticClass(fullname: String) = {
+ if (self.forMSIL)
+ throw new UnsupportedOperationException("Scala reflection not available on this platform")
+
+ getClass(newTypeName(fullname))
+ }
+
+ def staticModule(fullname: String) = {
+ if (self.forMSIL)
+ throw new UnsupportedOperationException("Scala reflection not available on this platform")
+
+ getModule(newTermName(fullname))
+ }
+
+ private def getClass(fullname: Name): Symbol = {
+ var result = getModuleOrClass(fullname.toTypeName)
+ while (result.isAliasType) result = result.info.typeSymbol
+ result
+ }
+
+ private def getModule(fullname: Name): Symbol =
+ getModuleOrClass(fullname.toTermName)
+
+ private def getModuleOrClass(path: Name): Symbol =
+ getModuleOrClass(path, path.length)
+
+ private def getModuleOrClass(path: Name, len: Int): Symbol = {
+ val point = path lastPos('.', len - 1)
+ val owner =
+ if (point > 0) getModuleOrClass(path.toTermName, point)
+ else definitions.RootClass
+ val name = path subName (point + 1, len)
+ val sym = owner.info member name
+ val result = if (path.isTermName) sym.suchThat(_ hasFlag symtab.Flags.MODULE) else sym
+ if (result != NoSymbol) result
+ else {
+ if (settings.debug.value) { log(sym.info); log(sym.info.members) }//debug
+ if (owner.isRoot && isJavaClass(name.toString))
+ definitions.EmptyPackageClass.info decl name
+ else {
+ def info(msg: => String) = if (settings.verbose.value) println(msg)
+ info("*** missing: "+name+"/"+name.isTermName+"/"+owner+"/"+owner.hasPackageFlag+"/"+owner.info.decls.getClass)
+ MissingRequirementError.notFound((if (path.isTermName) "object " else "class ")+path)
+ }
+ }
+ }
+
+ private def isJavaClass(path: String): Boolean =
+ try {
+ val classpath = platform.classPath.asURLs
+ var classLoader = ScalaClassLoader.fromURLs(classpath)
+ Class.forName(path, true, classLoader)
+ true
+ } catch {
+ case (_: ClassNotFoundException) | (_: NoClassDefFoundError) | (_: IncompatibleClassChangeError) =>
+ false
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 6a30dc2a0f..b7d7f5d16f 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -12,7 +12,7 @@ import compat.Platform.currentTime
import scala.tools.util.{ Profiling, PathResolver }
import scala.collection.{ mutable, immutable }
import io.{ SourceReader, AbstractFile, Path }
-import reporters.{ Reporter, ConsoleReporter }
+import reporters.{ Reporter => NscReporter, ConsoleReporter }
import util.{ NoPosition, Exceptional, ClassPath, SourceFile, NoSourceFile, Statistics, StatisticsInfo, BatchSourceFile, ScriptSourceFile, ShowPickled, ScalaClassLoader, returning }
import scala.reflect.internal.pickling.{ PickleBuffer, PickleFormat }
import settings.{ AestheticSettings }
@@ -32,24 +32,25 @@ import backend.jvm.GenJVM
import backend.opt.{ Inliners, InlineExceptionHandlers, ClosureElimination, DeadCodeElimination }
import backend.icode.analysis._
-class Global(var currentSettings: Settings, var reporter: Reporter) extends SymbolTable
- with CompilationUnits
- with Plugins
- with PhaseAssembly
- with Trees
- with Reifiers
- with TreePrinters
- with DocComments
- with MacroContext
- with symtab.Positions {
+class Global(var currentSettings: Settings, var reporter: NscReporter) extends SymbolTable
+ with ClassLoaders
+ with ToolBoxes
+ with CompilationUnits
+ with Plugins
+ with PhaseAssembly
+ with Trees
+ with FreeVars
+ with TreePrinters
+ with DocComments
+ with Positions {
override def settings = currentSettings
-
+
import definitions.{ findNamedMember, findMemberFromRoot }
// alternate constructors ------------------------------------------
- def this(reporter: Reporter) =
+ def this(reporter: NscReporter) =
this(new Settings(err => reporter.error(null, err)), reporter)
def this(settings: Settings) =
@@ -61,7 +62,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
type AbstractFileType = scala.tools.nsc.io.AbstractFile
def mkAttributedQualifier(tpe: Type, termSym: Symbol): Tree = gen.mkAttributedQualifier(tpe, termSym)
-
+
def picklerPhase: Phase = if (currentRun.isDefined) currentRun.picklerPhase else NoPhase
// platform specific elements
@@ -78,6 +79,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
// sub-components --------------------------------------------------
/** Generate ASTs */
+ type TreeGen = scala.tools.nsc.ast.TreeGen
+
object gen extends {
val global: Global.this.type = Global.this
} with TreeGen {
@@ -127,7 +130,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
/** Print tree in detailed form */
object nodePrinters extends {
val global: Global.this.type = Global.this
- } with NodePrinters with ReifyPrinters {
+ } with NodePrinters {
infolevel = InfoLevel.Verbose
}
@@ -137,7 +140,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
} with TreeBrowsers
val nodeToString = nodePrinters.nodeToString
- val reifiedNodeToString = nodePrinters.reifiedNodeToString
val treeBrowser = treeBrowsers.create()
// ------------ Hooks for interactive mode-------------------------
@@ -215,15 +217,11 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
def logAfterEveryPhase[T](msg: String)(op: => T) {
log("Running operation '%s' after every phase.\n".format(msg) + describeAfterEveryPhase(op))
}
-
+
def shouldLogAtThisPhase = (
(settings.log.isSetByUser)
&& ((settings.log containsPhase globalPhase) || (settings.log containsPhase phase))
)
- def atPhaseStackMessage = atPhaseStack match {
- case Nil => ""
- case ps => ps.reverseMap("->" + _).mkString("(", " ", ")")
- }
// Over 200 closure objects are eliminated by inlining this.
@inline final def log(msg: => AnyRef) {
if (shouldLogAtThisPhase)
@@ -323,7 +321,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
def showNames = List(showClass, showObject).flatten
def showPhase = isActive(settings.Yshow)
def showSymbols = settings.Yshowsyms.value
- def showTrees = settings.Xshowtrees.value
+ def showTrees = settings.Xshowtrees.value || settings.XshowtreesCompact.value || settings.XshowtreesStringified.value
val showClass = optSetting[String](settings.Xshowcls) map (x => splitClassAndPhase(x, false))
val showObject = optSetting[String](settings.Xshowobj) map (x => splitClassAndPhase(x, true))
@@ -1006,7 +1004,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
/** Set phase to a newly created syntaxAnalyzer and call definitions.init. */
val parserPhase: Phase = syntaxAnalyzer.newPhase(NoPhase)
phase = parserPhase
- definitions.init
+ definitions.init()
// Flush the cache in the terminal phase: the chain could have been built
// before without being used. (This happens in the interpreter.)
@@ -1112,7 +1110,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
def phaseNamed(name: String): Phase =
findOrElse(firstPhase.iterator)(_.name == name)(NoPhase)
-
+
/** All phases as of 3/2012 here for handiness; the ones in
* active use uncommented.
*/
@@ -1585,7 +1583,7 @@ object Global {
* This allows the use of a custom Global subclass with the software which
* wraps Globals, such as scalac, fsc, and the repl.
*/
- def fromSettings(settings: Settings, reporter: Reporter): Global = {
+ def fromSettings(settings: Settings, reporter: NscReporter): Global = {
// !!! The classpath isn't known until the Global is created, which is too
// late, so we have to duplicate it here. Classpath is too tightly coupled,
// it is a construct external to the compiler and should be treated as such.
@@ -1593,7 +1591,7 @@ object Global {
val loader = ScalaClassLoader.fromURLs(new PathResolver(settings).result.asURLs, parentLoader)
val name = settings.globalClass.value
val clazz = Class.forName(name, true, loader)
- val cons = clazz.getConstructor(classOf[Settings], classOf[Reporter])
+ val cons = clazz.getConstructor(classOf[Settings], classOf[NscReporter])
cons.newInstance(settings, reporter).asInstanceOf[Global]
}
@@ -1601,7 +1599,7 @@ object Global {
/** A global instantiated this way honors -Yglobal-class setting, and
* falls back on calling the Global constructor directly.
*/
- def apply(settings: Settings, reporter: Reporter): Global = {
+ def apply(settings: Settings, reporter: NscReporter): Global = {
val g = (
if (settings.globalClass.isDefault) null
else try fromSettings(settings, reporter) catch { case x =>
diff --git a/src/compiler/scala/tools/nsc/MacroContext.scala b/src/compiler/scala/tools/nsc/MacroContext.scala
deleted file mode 100644
index 9ea1f87125..0000000000
--- a/src/compiler/scala/tools/nsc/MacroContext.scala
+++ /dev/null
@@ -1,10 +0,0 @@
-package scala.tools.nsc
-
-import symtab.Flags._
-
-trait MacroContext extends reflect.macro.Context { self: Global =>
-
- def captureVariable(vble: Symbol): Unit = vble setFlag CAPTURED
-
- def referenceCapturedVariable(id: Ident): Tree = ReferenceToBoxed(id)
-}
diff --git a/src/compiler/scala/tools/nsc/ReflectGlobal.scala b/src/compiler/scala/tools/nsc/ReflectGlobal.scala
index 3132a9987d..68a6a4d336 100644
--- a/src/compiler/scala/tools/nsc/ReflectGlobal.scala
+++ b/src/compiler/scala/tools/nsc/ReflectGlobal.scala
@@ -5,7 +5,7 @@ import reporters.Reporter
/** A version of Global that uses reflection to get class
* infos, instead of reading class or source files.
*/
-class ReflectGlobal(currentSettings: Settings, reporter: Reporter)
+class ReflectGlobal(currentSettings: Settings, reporter: Reporter, var classLoader: ClassLoader)
extends Global(currentSettings, reporter) with reflect.runtime.SymbolTable {
override def transformedType(sym: Symbol) =
@@ -13,4 +13,9 @@ class ReflectGlobal(currentSettings: Settings, reporter: Reporter)
uncurry.transformInfo(sym,
refChecks.transformInfo(sym, sym.info)))
+ override def staticClass(fullname: String) =
+ super[SymbolTable].staticClass(fullname)
+
+ override def staticModule(fullname: String) =
+ super[SymbolTable].staticModule(fullname)
}
diff --git a/src/compiler/scala/tools/nsc/ReflectMain.scala b/src/compiler/scala/tools/nsc/ReflectMain.scala
index 7167f5aa27..f9a18abc25 100644
--- a/src/compiler/scala/tools/nsc/ReflectMain.scala
+++ b/src/compiler/scala/tools/nsc/ReflectMain.scala
@@ -1,7 +1,16 @@
package scala.tools.nsc
+import util.ScalaClassLoader
+import tools.util.PathResolver
+import util.ClassPath.DefaultJavaContext
+
object ReflectMain extends Driver {
- override def newCompiler(): Global = new ReflectGlobal(settings, reporter)
+ private def reflectionClassloaderFromSettings(settings: Settings) = {
+ val classpath = new PathResolver(settings).result
+ ScalaClassLoader.fromURLs(classpath.asURLs, getClass.getClassLoader)
+ }
+
+ override def newCompiler(): Global = new ReflectGlobal(settings, reporter, reflectionClassloaderFromSettings(settings))
} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/ToolBoxes.scala b/src/compiler/scala/tools/nsc/ToolBoxes.scala
new file mode 100644
index 0000000000..eb298833b8
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ToolBoxes.scala
@@ -0,0 +1,85 @@
+package scala.tools.nsc
+
+import util.ScalaClassLoader
+
+trait ToolBoxes { self: Global =>
+
+ import self.{Reporter => ApiReporter}
+
+ def mkToolBox(reporter: ApiReporter = mkSilentReporter(), options: String = "") = new ToolBox(reporter, options)
+
+ class ToolBox(val reporter: ApiReporter, val options: String) extends AbsToolBox {
+ def typeCheck(tree0: Tree, pt: Type = WildcardType, freeTypes: Map[FreeType, Type] = Map[FreeType, Type](), silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree = {
+ val tree = substituteFreeTypes(tree0, freeTypes)
+ val currentTyper = typer
+ val wrapper1 = if (!withImplicitViewsDisabled) (currentTyper.context.withImplicitsEnabled[Tree] _) else (currentTyper.context.withImplicitsDisabled[Tree] _)
+ val wrapper2 = if (!withMacrosDisabled) (currentTyper.context.withMacrosEnabled[Tree] _) else (currentTyper.context.withMacrosDisabled[Tree] _)
+ def wrapper (tree: => Tree) = wrapper1(wrapper2(tree))
+ wrapper(currentTyper.silent(_.typed(tree, analyzer.EXPRmode, pt)) match {
+ case analyzer.SilentResultValue(result) =>
+ result
+ case error @ analyzer.SilentTypeError(_) =>
+ if (!silent) throw new ToolBoxError(this, "reflective typecheck has failed: %s".format(error.err.errMsg))
+ EmptyTree
+ })
+ }
+
+ def inferImplicitValue(pt: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false): Tree =
+ // todo. implement this
+ ???
+
+ def inferImplicitView(tree: Tree, from: Type, to: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, reportAmbiguous: Boolean = true): Tree =
+ // todo. implement this
+ ???
+
+ def resetAllAttrs[T <: Tree](tree: T): T =
+ self.resetAllAttrs(tree)
+
+ def resetLocalAttrs[T <: Tree](tree: T): T =
+ self.resetLocalAttrs(tree)
+
+ def runExpr(tree0: Tree, freeTypes: Map[FreeType, Type] = Map[FreeType, Type]()): Any = {
+ var tree = substituteFreeTypes(tree0, freeTypes)
+ // need to reset the tree, otherwise toolbox will refuse to work with it
+ tree = resetAllAttrs(tree0.duplicate)
+ val imported = importer.importTree(tree)
+ val toolBox = libraryClasspathMirror.mkToolBox(reporter.asInstanceOf[libraryClasspathMirror.Reporter], options)
+ try toolBox.runExpr(imported)
+ catch {
+ case ex: toolBox.ToolBoxError =>
+ throw new ToolBoxError(this, ex.message, ex.cause)
+ }
+ }
+
+ // [Eugene] how do I make this work without casts?
+ // private lazy val importer = libraryClasspathMirror.mkImporter(self)
+ private lazy val importer = libraryClasspathMirror.mkImporter(self).asInstanceOf[libraryClasspathMirror.Importer { val from: self.type }]
+
+ private lazy val libraryClasspathMirror = {
+ if (self.forMSIL)
+ throw new UnsupportedOperationException("Scala reflection not available on this platform")
+
+ val libraryClassLoader = {
+ val classpath = self.classPath.asURLs
+ var loader: ClassLoader = ScalaClassLoader.fromURLs(classpath, self.getClass.getClassLoader)
+
+ // [Eugene] a heuristic to detect REPL
+ if (self.settings.exposeEmptyPackage.value) {
+ import scala.tools.nsc.interpreter._
+ val virtualDirectory = self.settings.outputDirs.getSingleOutput.get
+ loader = new AbstractFileClassLoader(virtualDirectory, loader) {}
+ }
+
+ loader
+ }
+
+ new scala.reflect.runtime.Mirror(libraryClassLoader)
+ }
+
+ class ToolBoxError(val toolBox: ToolBox, val message: String, val cause: Throwable = null) extends Throwable(message, cause)
+
+ object ToolBoxError extends ToolBoxErrorExtractor {
+ def unapply(error: ToolBoxError): Option[(ToolBox, String)] = Some((error.toolBox, error.message))
+ }
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala
index d3f4688d4b..ff4e2f3fb5 100755
--- a/src/compiler/scala/tools/nsc/ast/DocComments.scala
+++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala
@@ -7,7 +7,7 @@ package scala.tools.nsc
package ast
import symtab._
-import reporters.Reporter
+import reporters.{Reporter => NscReporter}
import util.{Position, NoPosition}
import util.DocStrings._
import scala.reflect.internal.Chars._
@@ -21,7 +21,7 @@ trait DocComments { self: Global =>
var cookedDocComments = Map[Symbol, String]()
- def reporter: Reporter
+ def reporter: NscReporter
/** The raw doc comment map */
val docComments = mutable.HashMap[Symbol, DocComment]()
@@ -495,8 +495,7 @@ trait DocComments { self: Global =>
val tpe = getType(repl.trim)
if (tpe != NoType) tpe
else {
- val alias1 = alias.cloneSymbol(definitions.RootClass)
- alias1.name = newTypeName(repl)
+ val alias1 = alias.cloneSymbol(definitions.RootClass, alias.rawflags, newTypeName(repl))
typeRef(NoPrefix, alias1, Nil)
}
case None =>
@@ -523,10 +522,9 @@ trait DocComments { self: Global =>
}
for (defn <- defined) yield {
- val useCase = defn.cloneSymbol
- useCase.owner = sym.owner
- useCase.flags = sym.flags
- useCase.setFlag(Flags.SYNTHETIC).setInfo(substAliases(defn.info).asSeenFrom(site.thisType, sym.owner))
+ defn.cloneSymbol(sym.owner, sym.flags | Flags.SYNTHETIC) modifyInfo (info =>
+ substAliases(info).asSeenFrom(site.thisType, sym.owner)
+ )
}
}
}
diff --git a/src/compiler/scala/tools/nsc/ast/FreeVars.scala b/src/compiler/scala/tools/nsc/ast/FreeVars.scala
new file mode 100644
index 0000000000..1bf36e8bf2
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/FreeVars.scala
@@ -0,0 +1,26 @@
+package scala.tools.nsc
+package ast
+
+trait FreeVars extends reflect.internal.FreeVars { self: Global =>
+
+ import self._
+ import definitions._
+ import treeInfo._
+
+ def logFreeVars(position: Position, reified: Tree): Unit = {
+ if (settings.logFreeTerms.value || settings.logFreeTypes.value) {
+ reified match {
+ case Reified(_, symbolTable, _) =>
+ // logging free vars only when they are untyped prevents avalanches of duplicate messages
+ symbolTable foreach {
+ case FreeTermDef(_, _, binding, origin) if settings.logFreeTerms.value && binding.tpe == null =>
+ reporter.echo(position, "free term: %s %s".format(showRaw(binding), origin))
+ case FreeTypeDef(_, _, binding, origin) if settings.logFreeTypes.value && binding.tpe == null =>
+ reporter.echo(position, "free type: %s %s".format(showRaw(binding), origin))
+ case _ =>
+ // do nothing
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala
index acbdcd501f..c79ca1206e 100644
--- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala
+++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala
@@ -27,24 +27,24 @@ abstract class NodePrinters {
def nodeToString: Tree => String =
if (sys.props contains "scala.colors") nodeToColorizedString
else nodeToRegularString
-
+
object nodeToRegularString extends DefaultPrintAST with (Tree => String) {
def apply(tree: Tree) = stringify(tree)
}
-
+
object nodeToColorizedString extends ColorPrintAST with (Tree => String) {
def apply(tree: Tree) = stringify(tree)
}
trait ColorPrintAST extends DefaultPrintAST {
import scala.tools.util.color._
-
+
def keywordColor = Cyan
def typeColor = Yellow
def termColor = Blue
def flagColor = Red
def literalColor = Green
-
+
override def showFlags(tree: MemberDef) =
super.showFlags(tree) in flagColor.bright
@@ -81,7 +81,7 @@ abstract class NodePrinters {
if (tpe == null || tpe == NoType) ""
else "tree.tpe=" + tpe
}
-
+
def showAttributes(tree: Tree): String = {
if (infolevel == InfoLevel.Quiet) ""
else {
@@ -90,7 +90,7 @@ abstract class NodePrinters {
}
}
}
-
+
trait PrintAST {
private val buf = new StringBuilder
private var level = 0
@@ -101,7 +101,7 @@ abstract class NodePrinters {
def showLiteral(lit: Literal): String
def showTypeTree(tt: TypeTree): String
def showAttributes(tree: Tree): String // symbol and type
-
+
def showRefTreeName(tree: Tree): String = tree match {
case SelectFromTypeTree(qual, name) => showRefTreeName(qual) + "#" + showName(name)
case Select(qual, name) => showRefTreeName(qual) + "." + showName(name)
@@ -122,8 +122,14 @@ abstract class NodePrinters {
def stringify(tree: Tree): String = {
buf.clear()
- level = 0
- traverse(tree)
+ if (settings.XshowtreesStringified.value) buf.append(tree.toString + EOL)
+ if (settings.XshowtreesCompact.value) {
+ // todo. colors for compact representation
+ buf.append(showRaw(tree))
+ } else {
+ level = 0
+ traverse(tree)
+ }
buf.toString
}
def traverseAny(x: Any) {
@@ -134,7 +140,7 @@ abstract class NodePrinters {
}
}
def println(s: String) = printLine(s, "")
-
+
def printLine(value: String, comment: String) {
buf append " " * level
buf append value
@@ -183,7 +189,7 @@ abstract class NodePrinters {
traverseList("Nil", "argument")(args)
}
}
-
+
def printMultiline(tree: Tree)(body: => Unit) {
printMultiline(tree.printingPrefix, showAttributes(tree))(body)
}
@@ -299,7 +305,7 @@ abstract class NodePrinters {
}
case Template(parents, self, body) =>
printMultiline(tree) {
- val ps0 = parents map { p =>
+ val ps0 = parents map { p =>
if (p.tpe eq null) p match {
case x: RefTree => showRefTree(x)
case x => "" + x
@@ -339,7 +345,7 @@ abstract class NodePrinters {
traverseList("[]", "type parameter")(tparams)
traverse(rhs)
}
-
+
case PackageDef(pid, stats) =>
printMultiline("PackageDef", "")(pid :: stats foreach traverse)
diff --git a/src/compiler/scala/tools/nsc/ast/Positions.scala b/src/compiler/scala/tools/nsc/ast/Positions.scala
new file mode 100644
index 0000000000..83a67cfbe3
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/Positions.scala
@@ -0,0 +1,44 @@
+package scala.tools.nsc
+package ast
+
+import scala.tools.nsc.util.{ SourceFile, Position, OffsetPosition, NoPosition }
+
+trait Positions extends scala.reflect.internal.Positions {
+ self: Global =>
+
+ def rangePos(source: SourceFile, start: Int, point: Int, end: Int) =
+ new OffsetPosition(source, point)
+
+ def validatePositions(tree: Tree) {}
+
+ // [Eugene] disabling this for now. imo it doesn't justify pollution of the public API
+ // override def _checkSetAnnotation(tree: Tree, annot: TreeAnnotation): Unit = {
+ // if (tree.pos != NoPosition && tree.pos != annot.pos) debugwarn("Overwriting annotation "+ tree.annotation +" of tree "+ tree +" with annotation "+ annot)
+ // // if ((tree.annotation.isInstanceOf[scala.tools.nsc.util.Position] || !annot.isInstanceOf[scala.tools.nsc.util.Position]) && tree.isInstanceOf[Block])
+ // // println("Updating block from "+ tree.annotation +" to "+ annot)
+ // }
+
+ class ValidatingPosAssigner extends PosAssigner {
+ var pos: Position = _
+ override def traverse(t: Tree) {
+ if (t eq EmptyTree) ()
+ else if (t.pos == NoPosition) super.traverse(t setPos pos)
+ else if (globalPhase.id <= currentRun.picklerPhase.id) {
+ // When we prune due to encountering a position, traverse the
+ // pruned children so we can warn about those lacking positions.
+ t.children foreach { c =>
+ if ((c eq EmptyTree) || (c eq emptyValDef)) ()
+ else if (c.pos == NoPosition) {
+ reporter.warning(t.pos, " Positioned tree has unpositioned child in phase " + globalPhase)
+ inform("parent: " + treeSymStatus(t))
+ inform(" child: " + treeSymStatus(c) + "\n")
+ }
+ }
+ }
+ }
+ }
+
+ override protected[this] lazy val posAssigner: PosAssigner =
+ if (settings.Yrangepos.value && settings.debug.value || settings.Yposdebug.value) new ValidatingPosAssigner
+ else new DefaultPosAssigner
+}
diff --git a/src/compiler/scala/tools/nsc/ast/Reifiers.scala b/src/compiler/scala/tools/nsc/ast/Reifiers.scala
deleted file mode 100644
index 7ece8bbd31..0000000000
--- a/src/compiler/scala/tools/nsc/ast/Reifiers.scala
+++ /dev/null
@@ -1,761 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2011 LAMP/EPFL
- * @author Gilles Dubochet
- */
-
-package scala.tools.nsc
-package ast
-
-import symtab._
-import Flags._
-import scala.reflect.api.Modifier._
-import scala.collection.{ mutable, immutable }
-import scala.collection.mutable.ListBuffer
-import scala.tools.nsc.util.FreshNameCreator
-import scala.runtime.ScalaRunTime.{ isAnyVal, isTuple }
-
-/** Given a tree or type, generate a tree that when executed at runtime produces the original tree or type.
- * See more info in the comments to `reify' in scala.reflect.macro.Context.
- *
- * @author Martin Odersky
- * @version 2.10
- */
-trait Reifiers { self: Global =>
-
- def reify(tree: Tree): Tree = {
- class Reifier {
- import definitions._
- import Reifier._
-
- final val scalaPrefix = "scala."
- final val localPrefix = "$local"
- final val memoizerName = "$memo"
-
- val reifyDebug = settings.Yreifydebug.value
-
- private val reifiableSyms = mutable.ArrayBuffer[Symbol]() // the symbols that are reified with the tree
- private val symIndex = mutable.HashMap[Symbol, Int]() // the index of a reifiable symbol in `reifiableSyms`
- private var boundSyms = Set[Symbol]() // set of all symbols that are bound in tree to be reified
-
- private def definedInLiftedCode(tpe: Type) =
- tpe exists (tp => boundSyms contains tp.typeSymbol)
-
- private def definedInLiftedCode(sym: Symbol) =
- boundSyms contains sym
-
- /**
- * Generate tree of the form
- *
- * { val $mr = scala.reflect.runtime.Mirror
- * $local1 = new TypeSymbol(owner1, NoPosition, name1)
- * ...
- * $localN = new TermSymbol(ownerN, NoPositiion, nameN)
- * $local1.setInfo(tpe1)
- * ...
- * $localN.setInfo(tpeN)
- * $localN.setAnnotations(annotsN)
- * rtree
- * }
- *
- * where
- *
- * - `$localI` are free type symbols in the environment, as well as local symbols
- * of refinement types.
- * - `tpeI` are the info's of `symI`
- * - `rtree` is code that generates `data` at runtime, maintaining all attributes.
- * - `data` is typically a tree or a type.
- */
- def reifyTopLevel(data: Any): Tree = {
- val rtree = reify(data)
- Block(mirrorAlias :: reifySymbolTableSetup, rtree)
- }
-
- private def isLocatable(sym: Symbol) =
- sym.isPackageClass || sym.owner.isClass || sym.isTypeParameter && sym.paramPos >= 0
-
- private def registerReifiableSymbol(sym: Symbol): Unit =
- if (!(symIndex contains sym)) {
- sym.owner.ownersIterator find (x => !isLocatable(x)) foreach registerReifiableSymbol
- symIndex(sym) = reifiableSyms.length
- reifiableSyms += sym
- }
-
- // helper methods
-
- private def localName(sym: Symbol): TermName =
- newTermName(localPrefix + symIndex(sym))
-
- private def call(fname: String, args: Tree*): Tree =
- Apply(termPath(fname), args.toList)
-
- private def mirrorSelect(name: String): Tree =
- termPath(nme.MIRROR_PREFIX + name)
-
- private def mirrorCall(name: TermName, args: Tree*): Tree =
- call("" + (nme.MIRROR_PREFIX append name), args: _*)
-
- private def mirrorCall(name: String, args: Tree*): Tree =
- call(nme.MIRROR_PREFIX + name, args: _*)
-
- private def mirrorFactoryCall(value: Product, args: Tree*): Tree =
- mirrorFactoryCall(value.productPrefix, args: _*)
-
- private def mirrorFactoryCall(prefix: String, args: Tree*): Tree =
- mirrorCall(prefix, args: _*)
-
- private def scalaFactoryCall(name: String, args: Tree*): Tree =
- call(scalaPrefix + name + ".apply", args: _*)
-
- private def mkList(args: List[Tree]): Tree =
- scalaFactoryCall("collection.immutable.List", args: _*)
-
- private def reifyModifiers(m: Modifiers) =
- mirrorCall("modifiersFromInternalFlags", reify(m.flags), reify(m.privateWithin), reify(m.annotations))
-
- private def reifyAggregate(name: String, args: Any*) =
- scalaFactoryCall(name, (args map reify).toList: _*)
-
- /**
- * Reify a list
- */
- private def reifyList(xs: List[Any]): Tree =
- mkList(xs map reify)
-
- /**
- * Reify an array
- */
- private def reifyArray(xs: Array[_]): Tree =
- // @xeno.by: doesn't work for Array(LiteralAnnotArg(...))
- // because we cannot generate manifests for path-dependent types
- scalaFactoryCall(nme.Array, xs map reify: _*)
-
- /** Reify a name */
- private def reifyName(name: Name) =
- mirrorCall(if (name.isTypeName) "newTypeName" else "newTermName", Literal(Constant(name.toString)))
-
- private def isFree(sym: Symbol) =
- !(symIndex contains sym)
-
- /**
- * Reify a reference to a symbol
- */
- private def reifySymRef(sym: Symbol): Tree = {
- symIndex get sym match {
- case Some(idx) =>
- Ident(localName(sym))
- case None =>
- if (sym == NoSymbol)
- mirrorSelect("NoSymbol")
- else if (sym == RootPackage)
- mirrorSelect("definitions.RootPackage")
- else if (sym == RootClass)
- mirrorSelect("definitions.RootClass")
- else if (sym == EmptyPackage)
- mirrorSelect("definitions.EmptyPackage")
- else if (sym.isModuleClass)
- Select(reifySymRef(sym.sourceModule), "moduleClass")
- else if (sym.isStatic && sym.isClass)
- mirrorCall("staticClass", reify(sym.fullName))
- else if (sym.isStatic && sym.isModule)
- mirrorCall("staticModule", reify(sym.fullName))
- else if (isLocatable(sym))
- if (sym.isTypeParameter)
- mirrorCall("selectParam", reify(sym.owner), reify(sym.paramPos))
- else {
- if (reifyDebug) println("locatable: " + sym + " " + sym.isPackageClass + " " + sym.owner + " " + sym.isTypeParameter)
- val rowner = reify(sym.owner)
- val rname = reify(sym.name.toString)
- if (sym.isType)
- mirrorCall("selectType", rowner, rname)
- else if (sym.isMethod && sym.owner.isClass && sym.owner.info.decl(sym.name).isOverloaded) {
- val index = sym.owner.info.decl(sym.name).alternatives indexOf sym
- assert(index >= 0, sym)
- mirrorCall("selectOverloadedMethod", rowner, rname, reify(index))
- } else
- mirrorCall("selectTerm", rowner, rname)
- }
- else {
- if (sym.isTerm) {
- if (reifyDebug) println("Free: " + sym)
- val symtpe = lambdaLift.boxIfCaptured(sym, sym.tpe, erasedTypes = false)
- def markIfCaptured(arg: Ident): Tree =
- if (sym.isCapturedVariable) referenceCapturedVariable(arg) else arg
- mirrorCall("newFreeVar", reify(sym.name.toString), reify(symtpe), markIfCaptured(Ident(sym)))
- } else {
- if (reifyDebug) println("Late local: " + sym)
- registerReifiableSymbol(sym)
- reifySymRef(sym)
- }
- }
- }
- }
-
- /**
- * reify the creation of a symbol
- */
- private def reifySymbolDef(sym: Symbol): Tree = {
- if (reifyDebug) println("reify sym def " + sym)
-
- ValDef(NoMods, localName(sym), TypeTree(),
- Apply(
- Select(reify(sym.owner), "newNestedSymbol"),
- List(reify(sym.name), reify(sym.pos), Literal(Constant(sym.flags)))
- )
- )
- }
-
- /**
- * Generate code to add type and annotation info to a reified symbol
- */
- private def fillInSymbol(sym: Symbol): Tree = {
- val rset = Apply(Select(reifySymRef(sym), nme.setTypeSignature), List(reifyType(sym.info)))
- if (sym.annotations.isEmpty) rset
- else Apply(Select(rset, nme.setAnnotations), List(reify(sym.annotations)))
- }
-
- /** Reify a scope */
- private def reifyScope(scope: Scope): Tree = {
- scope foreach registerReifiableSymbol
- mirrorCall(nme.newScopeWith, scope.toList map reifySymRef: _*)
- }
-
- /** Reify a list of symbols that need to be created */
- private def reifySymbols(syms: List[Symbol]): Tree = {
- syms foreach registerReifiableSymbol
- mkList(syms map reifySymRef)
- }
-
- /** Reify a type that defines some symbols */
- private def reifyTypeBinder(value: Product, bound: List[Symbol], underlying: Type): Tree =
- mirrorFactoryCall(value, reifySymbols(bound), reify(underlying))
-
- /** Reify a type */
- private def reifyType(tpe0: Type): Tree = {
- val tpe = tpe0.normalize
-
- if (tpe.isErroneous)
- CannotReifyErroneousType(tpe)
- if (definedInLiftedCode(tpe))
- CannotReifyTypeInvolvingBoundType(tpe)
-
- val tsym = tpe.typeSymbol
- if (tsym.isClass && tpe == tsym.typeConstructor && tsym.isStatic)
- Select(reifySymRef(tpe.typeSymbol), nme.asTypeConstructor)
- else tpe match {
- case t @ NoType =>
- reifyMirrorObject(t)
- case t @ NoPrefix =>
- reifyMirrorObject(t)
- case tpe @ ThisType(clazz) if clazz.isModuleClass && clazz.isStatic =>
- mirrorCall(nme.thisModuleType, reify(clazz.fullName))
- case t @ RefinedType(parents, decls) =>
- registerReifiableSymbol(tpe.typeSymbol)
- mirrorFactoryCall(t, reify(parents), reify(decls), reify(t.typeSymbol))
- case t @ ClassInfoType(parents, decls, clazz) =>
- registerReifiableSymbol(clazz)
- mirrorFactoryCall(t, reify(parents), reify(decls), reify(t.typeSymbol))
- case t @ ExistentialType(tparams, underlying) =>
- reifyTypeBinder(t, tparams, underlying)
- case t @ PolyType(tparams, underlying) =>
- reifyTypeBinder(t, tparams, underlying)
- case t @ MethodType(params, restpe) =>
- reifyTypeBinder(t, params, restpe)
- case t @ AnnotatedType(anns, underlying, selfsym) =>
- val saved1 = reifySymbols
- val saved2 = reifyTypes
-
- try {
- // one more quirk of reifying annotations
- //
- // when reifying AnnotatedTypes we need to reify all the types and symbols of inner ASTs
- // that's because a lot of logic expects post-typer trees to have non-null tpes
- //
- // Q: reified trees are pre-typer, so there's shouldn't be a problem.
- // reflective typechecker will fill in missing symbols and types, right?
- // A: actually, no. annotation ASTs live inside AnnotatedTypes,
- // and insides of the types is the place where typechecker doesn't look.
- reifySymbols = true
- reifyTypes = true
- if (reifyDebug) println("reify AnnotatedType: " + tpe)
- reifyProductUnsafe(tpe)
- } finally {
- reifySymbols = saved1
- reifyTypes = saved2
- }
- case _ =>
- reifyProductUnsafe(tpe)
- }
- }
-
- var reifySymbols = false
- var reifyTypes = false
-
- /** Preprocess a tree before reification */
- private def trimTree(tree: Tree): Tree = {
- def trimSyntheticCaseClassMembers(deff: Tree, stats: List[Tree]) = {
- var stats1 = stats filterNot (stat => stat.isDef && {
- if (stat.symbol.isCaseAccessorMethod && reifyDebug) println("discarding case accessor method: " + stat)
- stat.symbol.isCaseAccessorMethod
- })
- stats1 = stats1 filterNot (memberDef => memberDef.isDef && {
- val isSynthetic = memberDef.symbol.isSynthetic
- // @xeno.by: this doesn't work for local classes, e.g. for ones that are top-level to a quasiquote (see comments to companionClass)
- // that's why I replace the check with an assumption that all synthetic members are, in fact, generated of case classes
-// val isCaseMember = deff.symbol.isCaseClass || deff.symbol.companionClass.isCaseClass
- val isCaseMember = true
- if (isSynthetic && isCaseMember && reifyDebug) println("discarding case class synthetic def: " + memberDef)
- isSynthetic && isCaseMember
- })
- stats1 = stats1 map {
- case valdef @ ValDef(mods, name, tpt, rhs) if valdef.symbol.isCaseAccessor =>
- if (reifyDebug) println("resetting visibility of case accessor field: " + valdef)
- val Modifiers(flags, privateWithin, annotations) = mods
- val flags1 = flags & ~Flags.LOCAL & ~Flags.PRIVATE
- val mods1 = Modifiers(flags1, privateWithin, annotations)
- ValDef(mods1, name, tpt, rhs).copyAttrs(valdef)
- case stat =>
- stat
- }
- stats1
- }
-
- def trimSyntheticCaseClassCompanions(stats: List[Tree]) =
- stats diff (stats collect { case moddef: ModuleDef => moddef } filter (moddef => {
- val isSynthetic = moddef.symbol.isSynthetic
- // @xeno.by: this doesn't work for local classes, e.g. for ones that are top-level to a quasiquote (see comments to companionClass)
- // that's why I replace the check with an assumption that all synthetic modules are, in fact, companions of case classes
-// val isCaseCompanion = moddef.symbol.companionClass.isCaseClass
- val isCaseCompanion = true
- // @xeno.by: we also have to do this ugly hack for the very same reason described above
- // normally this sort of stuff is performed in reifyTree, which binds related symbols, however, local companions will be out of its reach
- if (reifyDebug) println("boundSym: "+ moddef.symbol)
- boundSyms += moddef.symbol
- if (isSynthetic && isCaseCompanion && reifyDebug) println("discarding synthetic case class companion: " + moddef)
- isSynthetic && isCaseCompanion
- }))
-
- tree match {
- case tree if tree.isErroneous =>
- tree
- case ta @ TypeApply(hk, ts) =>
- def isErased(tt: TypeTree) = tt.tpe != null && definedInLiftedCode(tt.tpe) && tt.original == null
- val discard = ts collect { case tt: TypeTree => tt } exists isErased
- if (reifyDebug && discard) println("discarding TypeApply: " + tree)
- if (discard) hk else ta
- case classDef @ ClassDef(mods, name, params, impl) =>
- val Template(parents, self, body) = impl
- val body1 = trimSyntheticCaseClassMembers(classDef, body)
- var impl1 = Template(parents, self, body1).copyAttrs(impl)
- ClassDef(mods, name, params, impl1).copyAttrs(classDef)
- case moduledef @ ModuleDef(mods, name, impl) =>
- val Template(parents, self, body) = impl
- val body1 = trimSyntheticCaseClassMembers(moduledef, body)
- var impl1 = Template(parents, self, body1).copyAttrs(impl)
- ModuleDef(mods, name, impl1).copyAttrs(moduledef)
- case template @ Template(parents, self, body) =>
- val body1 = trimSyntheticCaseClassCompanions(body)
- Template(parents, self, body1).copyAttrs(template)
- case block @ Block(stats, expr) =>
- val stats1 = trimSyntheticCaseClassCompanions(stats)
- Block(stats1, expr).copyAttrs(block)
- case valdef @ ValDef(mods, name, tpt, rhs) if valdef.symbol.isLazy =>
- if (reifyDebug) println("dropping $lzy in lazy val's name: " + tree)
- val name1 = if (name endsWith nme.LAZY_LOCAL) name dropRight nme.LAZY_LOCAL.length else name
- ValDef(mods, name1, tpt, rhs).copyAttrs(valdef)
- case unapply @ UnApply(fun, args) =>
- def extractExtractor(tree: Tree): Tree = {
- val Apply(fun, args) = tree
- args match {
- case List(Ident(special)) if special == nme.SELECTOR_DUMMY =>
- val Select(extractor, flavor) = fun
- assert(flavor == nme.unapply || flavor == nme.unapplySeq)
- extractor
- case _ =>
- extractExtractor(fun)
- }
- }
-
- if (reifyDebug) println("unapplying unapply: " + tree)
- val fun1 = extractExtractor(fun)
- Apply(fun1, args).copyAttrs(unapply)
- case _ =>
- tree
- }
- }
-
- /** Reify a tree */
- private def reifyTree(tree0: Tree): Tree = {
- val tree = trimTree(tree0)
-
- var rtree = tree match {
- case tree if tree.isErroneous =>
- CannotReifyErroneousTree(tree)
- case self.EmptyTree =>
- reifyMirrorObject(EmptyTree)
- case self.emptyValDef =>
- mirrorSelect(nme.emptyValDef)
- case This(_) if tree.symbol != NoSymbol && !(boundSyms contains tree.symbol) =>
- reifyFree(tree)
- case Ident(_) if tree.symbol != NoSymbol && !(boundSyms contains tree.symbol) =>
- if (tree.symbol.isVariable && tree.symbol.owner.isTerm) {
- if (reifyDebug) println("captured variable: " + tree.symbol)
- captureVariable(tree.symbol) // Note order dependency: captureVariable needs to come before reifyTree here.
- mirrorCall("Select", reifyFree(tree), reifyName(nme.elem))
- } else reifyFree(tree)
- case tt: TypeTree if (tt.tpe != null) =>
- reifyTypeTree(tt)
- case Literal(constant @ Constant(tpe: Type)) if boundSyms exists (tpe contains _) =>
- CannotReifyClassOfBoundType(tree, tpe)
- case Literal(constant @ Constant(sym: Symbol)) if boundSyms contains sym =>
- CannotReifyClassOfBoundEnum(tree, constant.tpe)
- case tree if tree.isDef =>
- if (reifyDebug) println("boundSym: %s of type %s".format(tree.symbol, (tree.productIterator.toList collect { case tt: TypeTree => tt } headOption).getOrElse(TypeTree(tree.tpe))))
- boundSyms += tree.symbol
-
- bindRelatedSymbol(tree.symbol.sourceModule, "sourceModule")
- bindRelatedSymbol(tree.symbol.moduleClass, "moduleClass")
- bindRelatedSymbol(tree.symbol.companionClass, "companionClass")
- bindRelatedSymbol(tree.symbol.companionModule, "companionModule")
- Some(tree.symbol) collect { case termSymbol: TermSymbol => bindRelatedSymbol(termSymbol.referenced, "referenced") }
- def bindRelatedSymbol(related: Symbol, name: String): Unit =
- if (related != null && related != NoSymbol) {
- if (reifyDebug) println("boundSym (" + name + "): " + related)
- boundSyms += related
- }
-
- val prefix = tree.productPrefix
- val elements = (tree.productIterator map {
- // annotations exist in two flavors:
- // 1) pre-typer ones that populate: a) Modifiers, b) Annotated nodes (irrelevant in this context)
- // 2) post-typer ones that dwell inside: a) sym.annotations, b) AnnotatedTypes (irrelevant in this context)
- //
- // here we process Modifiers that are involved in deftrees
- // AnnotatedTypes get reified elsewhere (currently, in ``reifyTypeTree'')
- case Modifiers(flags, privateWithin, annotations) =>
- assert(annotations.isEmpty) // should've been eliminated by the typer
- val postTyper = tree.symbol.annotations filter (_.original != EmptyTree)
- if (reifyDebug && !postTyper.isEmpty) println("reify symbol annotations for %s: %s".format(tree.symbol, tree.symbol.annotations))
- val preTyper = postTyper map toPreTyperAnnotation
- Modifiers(flags, privateWithin, preTyper)
- case x =>
- x
- }).toList
- reifyProduct(prefix, elements)
- case _ =>
- reifyProduct(tree)
- }
-
- // usually we don't reify symbols/types, because they can be re-inferred during subsequent reflective compilation
- // however, reification of AnnotatedTypes is special. see ``reifyType'' to find out why.
- if (reifySymbols && tree.hasSymbol) {
- if (reifyDebug) println("reifying symbol %s for tree %s".format(tree.symbol, tree))
- rtree = Apply(Select(rtree, nme.setSymbol), List(reifySymRef(tree.symbol)))
- }
- if (reifyTypes && tree.tpe != null) {
- if (reifyDebug) println("reifying type %s for tree %s".format(tree.tpe, tree))
- rtree = Apply(Select(rtree, nme.setType), List(reifyType(tree.tpe)))
- }
-
- rtree
- }
-
- /** Reify pre-typer representation of a type.
- *
- * NB: This is the trickiest part of reification!
- *
- * In most cases, we're perfectly fine to reify a Type itself (see ``reifyType'').
- * However if the type involves a symbol declared inside the quasiquote (i.e. registered in ``boundSyms''),
- * then we cannot reify it, or otherwise subsequent reflective compilation will fail.
- *
- * Why will it fail? Because reified deftrees (e.g. ClassDef(...)) will generate fresh symbols during that compilation,
- * so naively reified symbols will become out of sync, which brings really funny compilation errors and/or crashes, e.g.:
- * https://issues.scala-lang.org/browse/SI-5230
- *
- * To deal with this unpleasant fact, we need to fall back from types to equivalent trees (after all, parser trees don't contain any types, just trees, so it should be possible).
- * Luckily, these original trees get preserved for us in the ``original'' field when Trees get transformed into TypeTrees.
- * And if an original of a type tree is empty, we can safely assume that this type is non-essential (e.g. was inferred/generated by the compiler).
- * In that case the type can be omitted (e.g. reified as an empty TypeTree), since it will be inferred again later on.
- *
- * An important property of the original is that it isn't just a pre-typer tree.
- * It's actually kind of a post-typer tree with symbols assigned to its Idents (e.g. Ident("List") will contain a symbol that points to immutable.this.List).
- * This is very important, since subsequent reflective compilation won't have to resolve these symbols.
- * In general case, such resolution cannot be performed, since reification doesn't preserve lexical context,
- * which means that reflective compilation won't be aware of, say, imports that were provided when the reifee has been compiled.
- *
- * This workaround worked surprisingly well and allowed me to fix several important reification bugs, until the abstraction has leaked.
- * Suddenly I found out that in certain contexts original trees do not contain symbols, but are just parser trees.
- * To the moment I know only one such situation: typedAnnotations does not typecheck the annotation in-place, but rather creates new trees and typechecks them, so the original remains symless.
- * This is laboriously worked around in the code below. I hope this will be the only workaround in this department.
- */
- private def reifyTypeTree(tt: TypeTree): Tree = {
- if (definedInLiftedCode(tt.tpe)) {
- if (reifyDebug) println("reifyTypeTree, defined in lifted code: " + tt.tpe)
- if (tt.original != null) {
- val annotations = tt.tpe filter { _.isInstanceOf[AnnotatedType] } collect { case atp: AnnotatedType => atp.annotations } flatten
- val annmap = annotations map { ann => (ann.original, ann) } toMap
-
- // annotations exist in two flavors:
- // 1) pre-typer ones that populate: a) Modifiers (irrelevant in this context), b) Annotated nodes
- // 2) post-typer ones that dwell inside: a) sym.annotations (irrelevant in this context), b) AnnotatedTypes
- //
- // here we process AnnotatedTypes, since only they can be involved in TypeTrees
- // Modifiers get reified elsewhere (currently, in the "isDef" case of ``reifyTree'')
- //
- // the problem with annotations is that their originals don't preserve any symbols at all
- // read the comment to this method to find out why it's bad
- // that's why we transplant typechecked, i.e. symful, annotations onto original trees
- class AnnotationFixup extends self.Transformer {
- override def transform(tree: Tree) = tree match {
- case Annotated(ann0, args) =>
- assert(annmap contains ann0)
- val ann1 = annmap(ann0)
- val ann = toPreTyperAnnotation(ann1)
- Annotated(ann, transform(args))
- case _ =>
- tree
- }
- }
-
- if (reifyDebug) println("verdict: essential, reify as original")
- val patchedOriginal = new AnnotationFixup().transform(tt.original)
- reifyTree(patchedOriginal)
- } else {
- // type is deemed to be non-essential
- // erase it and hope that subsequent reflective compilation will be able to recreate it again
- if (reifyDebug) println("verdict: non-essential, discard")
- mirrorCall("TypeTree")
- }
- } else {
- var rtt = mirrorCall(nme.TypeTree, reifyType(tt.tpe))
- // @xeno.by: temporarily disabling reification of originals
- // subsequent reflective compilation will try to typecheck them
- // and this means that the reifier has to do additional efforts to ensure that this will succeed
- // additional efforts + no clear benefit = will be implemented later
-// if (tt.original != null) {
-// val setOriginal = Select(rtt, newTermName("setOriginal"))
-// val reifiedOriginal = reify(tt.original)
-// rtt = Apply(setOriginal, List(reifiedOriginal))
-// }
- rtt
- }
- }
-
- /** Reify post-typer representation of an annotation */
- private def reifyAnnotation(ann: AnnotationInfo): Tree =
- // @xeno.by: if you reify originals, you get SO when trying to reify AnnotatedTypes, so screw it - after all, it's not that important
- mirrorFactoryCall("AnnotationInfo", reifyType(ann.atp), reifyList(ann.args), reify(ann.assocs))
-
- /** Reify pre-typer representation of an annotation.
- * The trick here is to retain the symbols that have been populated during typechecking of the annotation.
- * If we do not do that, subsequent reflective compilation will fail.
- */
- private def toPreTyperAnnotation(ann: AnnotationInfo): Tree = {
- if (definedInLiftedCode(ann.atp)) {
- // todo. deconstruct reifiable tree from ann.original and ann.args+ann.assocs
- //
- // keep in mind that we can't simply use ann.original, because its args are symless
- // which means that any imported symbol (e.g. List) will crash subsequent reflective compilation
- // hint: if I had enough time, I'd try to extract reifiable annotation type from ann.original
- // and to apply its constructor to ann.args (that are symful, i.e. suitable for reification)
- //
- // also, if we pursue the route of reifying annotations defined in lifted code
- // we should think about how to provide types for all nodes of the return value
- // this will be necessary for reifying AnnotatedTypes, since ASTs inside ATs must all have non-null tpes
- // an alternative would be downgrading ATs to Annotated nodes, but this needs careful thinking
- // for now I just leave this as an implementation restriction
- CannotReifyAnnotationInvolvingBoundType(ann)
- } else {
- val args = if (ann.assocs.isEmpty) {
- ann.args
- } else {
- def toScalaAnnotation(jann: ClassfileAnnotArg): Tree = jann match {
- case LiteralAnnotArg(const) =>
- Literal(const)
- case ArrayAnnotArg(arr) =>
- Apply(Ident(definitions.ArrayModule), arr.toList map toScalaAnnotation)
- case NestedAnnotArg(ann) =>
- toPreTyperAnnotation(ann)
- }
-
- ann.assocs map { case (nme, arg) => AssignOrNamedArg(Ident(nme), toScalaAnnotation(arg)) }
- }
-
- New(ann.atp, args: _*)
- }
- }
-
- /**
- * Reify a free reference. The result will be either a mirror reference
- * to a global value, or else a mirror Literal.
- */
- private def reifyFree(tree: Tree): Tree = tree match {
- case This(_) if tree.symbol.isClass && !tree.symbol.isModuleClass =>
- val sym = tree.symbol
- if (reifyDebug) println("This for %s, reified as freeVar".format(sym))
- if (reifyDebug) println("Free: " + sym)
- val freeVar = mirrorCall("newFreeVar", reify(sym.name.toString), reify(sym.tpe), This(sym))
- mirrorCall(nme.Ident, freeVar)
- case This(_) =>
- if (reifyDebug) println("This for %s, reified as This".format(tree.symbol))
- mirrorCall(nme.This, reifySymRef(tree.symbol))
- case _ =>
- mirrorCall(nme.Ident, reifySymRef(tree.symbol))
- }
-
- // todo: consider whether we should also reify positions
- private def reifyPosition(pos: Position): Tree =
- reifyMirrorObject(NoPosition)
-
- // !!! we must eliminate these casts.
- private def reifyProductUnsafe(x: Any): Tree =
- if (x.isInstanceOf[Product]) reifyProduct(x.asInstanceOf[Product])
- else throw new Exception("%s of type %s cannot be cast to Product".format(x, x.getClass))
- private def reifyProduct(x: Product): Tree =
- reifyProduct(x.productPrefix, x.productIterator.toList)
- private def reifyProduct(prefix: String, elements: List[Any]): Tree = {
- // @xeno.by: reflection would be more robust, but, hey, this is a hot path
- if (prefix.startsWith("Tuple")) reifyAggregate(prefix, elements: _*)
- else mirrorCall(prefix, (elements map reify): _*)
- }
-
- /**
- * Reify a case object defined in Mirror
- */
- private def reifyMirrorObject(name: String): Tree = mirrorSelect(name)
- private def reifyMirrorObject(x: Product): Tree = reifyMirrorObject(x.productPrefix)
-
- private def isReifiableConstant(value: Any) = value match {
- case null => true // seems pretty reifable to me?
- case _: String => true
- case _ => isAnyVal(value)
- }
-
- /** Reify an arbitary value */
- private def reify(value: Any): Tree = value match {
- case tree: Tree => reifyTree(tree)
- case sym: Symbol => reifySymRef(sym)
- case tpe: Type => reifyType(tpe)
- case xs: List[_] => reifyList(xs)
- case xs: Array[_] => reifyArray(xs)
- case scope: Scope => reifyScope(scope)
- case x: Name => reifyName(x)
- case x: Position => reifyPosition(x)
- case x: Modifiers => reifyModifiers(x)
- case x: AnnotationInfo => reifyAnnotation(x)
- case _ =>
- if (isReifiableConstant(value)) Literal(Constant(value))
- else reifyProductUnsafe(value)
- }
-
- /**
- * An (unreified) path that refers to definition with given fully qualified name
- * @param mkName Creator for last portion of name (either TermName or TypeName)
- */
- private def path(fullname: String, mkName: String => Name): Tree = {
- val parts = fullname split "\\."
- val prefixParts = parts.init
- val lastName = mkName(parts.last)
- if (prefixParts.isEmpty) Ident(lastName)
- else {
- val prefixTree = ((Ident(prefixParts.head): Tree) /: prefixParts.tail)(Select(_, _))
- Select(prefixTree, lastName)
- }
- }
-
- /** An (unreified) path that refers to term definition with given fully qualified name */
- private def termPath(fullname: String): Tree = path(fullname, newTermName)
-
- /** An (unreified) path that refers to type definition with given fully qualified name */
- private def typePath(fullname: String): Tree = path(fullname, newTypeName)
-
- private def mirrorAlias =
- ValDef(NoMods, nme.MIRROR_SHORT, SingletonTypeTree(termPath(fullnme.MirrorPackage)), termPath(fullnme.MirrorPackage))
-
- /**
- * Generate code that generates a symbol table of all symbols registered in `reifiableSyms`
- */
- private def reifySymbolTableSetup: List[Tree] = {
- val symDefs, fillIns = new mutable.ArrayBuffer[Tree]
- var i = 0
- while (i < reifiableSyms.length) {
- // fillInSymbol might create new reifiableSyms, that's why this is done iteratively
- symDefs += reifySymbolDef(reifiableSyms(i))
- fillIns += fillInSymbol(reifiableSyms(i))
- i += 1
- }
-
- symDefs.toList ++ fillIns.toList
- }
- } // end of Reifier
-
- object Reifier {
- def CannotReifyPreTyperTree(tree: Tree) = {
- val msg = "pre-typer trees are not supported, consider typechecking the tree before passing it to the reifier"
- throw new ReifierError(tree.pos, msg)
- }
-
- def CannotReifyErroneousTree(tree: Tree) = {
- val msg = "erroneous trees are not supported, make sure that your tree typechecks successfully before passing it to the reifier"
- throw new ReifierError(tree.pos, msg)
- }
-
- def CannotReifyErroneousType(tpe: Type) = {
- val msg = "erroneous types are not supported, make sure that your tree typechecks successfully before passing it to the reifier"
- throw new ReifierError(NoPosition, msg)
- }
-
- def CannotReifyClassOfBoundType(tree: Tree, tpe: Type) = {
- val msg = "implementation restriction: cannot reify classOf[%s] which refers to a type declared inside the block being reified".format(tpe)
- throw new ReifierError(tree.pos, msg)
- }
-
- def CannotReifyClassOfBoundEnum(tree: Tree, tpe: Type) = {
- val msg = "implementation restriction: cannot reify classOf[%s] which refers to an enum declared inside the block being reified".format(tpe)
- throw new ReifierError(tree.pos, msg)
- }
-
- def CannotReifyTypeInvolvingBoundType(tpe: Type) = {
- val msg = "implementation restriction: cannot reify type %s which involves a symbol declared inside the block being reified".format(tpe)
- throw new ReifierError(NoPosition, msg)
- }
-
- def CannotReifyAnnotationInvolvingBoundType(ann: AnnotationInfo) = {
- val msg = "implementation restriction: cannot reify annotation @%s which involves a symbol declared inside the block being reified".format(ann)
- throw new ReifierError(ann.original.pos, msg)
- }
- } // end of Reifier
-
- // begin reify
- import Reifier._
- if (tree.tpe != null) {
- val saved = printTypings
- try {
- val reifyDebug = settings.Yreifydebug.value
- val debugTrace = util.trace when reifyDebug
- debugTrace("transforming = ")(if (settings.Xshowtrees.value) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString)
- debugTrace("transformed = ") {
- val reifier = new Reifier()
- val untyped = reifier.reifyTopLevel(tree)
-
- val reifyCopypaste = settings.Yreifycopypaste.value
- if (reifyCopypaste) {
- if (reifyDebug) println("=======================")
- println(reifiedNodeToString(untyped))
- if (reifyDebug) println("=======================")
- }
-
- untyped
- }
- } finally {
- printTypings = saved
- }
- } else {
- CannotReifyPreTyperTree(tree)
- }
- }
-
- /** A throwable signalling a reification error */
- class ReifierError(var pos: Position, val msg: String) extends Throwable(msg) {
- def this(msg: String) = this(NoPosition, msg)
- }
-}
diff --git a/src/compiler/scala/tools/nsc/ast/ReifyPrinters.scala b/src/compiler/scala/tools/nsc/ast/ReifyPrinters.scala
deleted file mode 100644
index fce59bb099..0000000000
--- a/src/compiler/scala/tools/nsc/ast/ReifyPrinters.scala
+++ /dev/null
@@ -1,75 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2011 LAMP/EPFL
- * @author Martin Odersky
- */
-
-package scala.tools.nsc
-package ast
-
-import compat.Platform.EOL
-import symtab._
-import Flags._
-
-trait ReifyPrinters { self: NodePrinters =>
-
- val global: Global
- import global._
-
- object reifiedNodeToString extends Function1[Tree, String] {
- def apply(tree: Tree): String = {
- import scala.reflect.api.Modifier
-
- // @PP: I fervently hope this is a test case or something, not anything being
- // depended upon. Of more fragile code I cannot conceive.
- // @eb: This stuff is only needed to debug-print out reifications in human-readable format
- // Rolling a full-fledged, robust TreePrinter would be several times more code.
- (for (line <- (tree.toString.split(EOL) drop 2 dropRight 1)) yield {
- var s = line.trim
- s = s.replace("$mr.", "")
- s = s.replace(".apply", "")
- s = s.replace("scala.collection.immutable.", "")
- s = "List\\[List\\[.*?\\].*?\\]".r.replaceAllIn(s, "List")
- s = "List\\[.*?\\]".r.replaceAllIn(s, "List")
- s = s.replace("immutable.this.Nil", "List()")
- s = s.replace("modifiersFromInternalFlags", "Modifiers")
- s = s.replace("Modifiers(0L, newTypeName(\"\"), List())", "Modifiers()")
- s = """Modifiers\((\d+)[lL], newTypeName\("(.*?)"\), List\((.*?)\)\)""".r.replaceAllIn(s, m => {
- val buf = new collection.mutable.ListBuffer[String]
-
- val annotations = m.group(3)
- if (buf.nonEmpty || annotations.nonEmpty)
- buf.append("List(" + annotations + ")")
-
- val privateWithin = "" + m.group(2)
- if (buf.nonEmpty || privateWithin != "")
- buf.append("newTypeName(\"" + privateWithin + "\")")
-
- val flags = m.group(1).toLong
- val s_flags = Flags.modifiersOfFlags(flags) map (_.sourceString) mkString ", "
- if (buf.nonEmpty || s_flags != "")
- buf.append("Set(" + s_flags + ")")
-
- "Modifiers(" + buf.reverse.mkString(", ") + ")"
- })
- s = """setInternalFlags\((\d+)L\)""".r.replaceAllIn(s, m => {
- val flags = m.group(1).toLong
- val mods = Flags.modifiersOfFlags(flags) map (_.sourceString)
- "setInternalFlags(flagsOfModifiers(List(" + mods.mkString(", ") + ")))"
- })
-
- s
- }) mkString EOL
- }
- }
-
-
- def printReifyCopypaste(tree: Tree) {
- val reifyDebug = settings.Yreifydebug.value
- if (reifyDebug) println("=======================")
- printReifyCopypaste1(tree)
- if (reifyDebug) println("=======================")
- }
-
- def printReifyCopypaste1(tree: Tree) {
- }
-} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
index 8703de4e18..2b75925d9a 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
@@ -292,7 +292,7 @@ trait TreeDSL {
def TRY(tree: Tree) = new TryStart(tree, Nil, EmptyTree)
def BLOCK(xs: Tree*) = Block(xs.init.toList, xs.last)
def NOT(tree: Tree) = Select(tree, Boolean_not)
- def SOME(xs: Tree*) = Apply(SomeModule, makeTupleTerm(xs.toList, true))
+ def SOME(xs: Tree*) = Apply(SomeClass.companionSymbol, makeTupleTerm(xs.toList, true))
/** Typed trees from symbols. */
def THIS(sym: Symbol) = gen.mkAttributedThis(sym)
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index ad26ccad5e..19d1e0a51a 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -207,22 +207,6 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL {
def mkSysErrorCall(message: String): Tree =
mkMethodCall(Sys_error, List(Literal(Constant(message))))
- /** A creator for a call to a scala.reflect.Manifest or ClassManifest factory method.
- *
- * @param full full or partial manifest (target will be Manifest or ClassManifest)
- * @param constructor name of the factory method (e.g. "classType")
- * @param tparg the type argument
- * @param args value arguments
- * @return the tree
- */
- def mkManifestFactoryCall(full: Boolean, constructor: String, tparg: Type, args: List[Tree]): Tree =
- mkMethodCall(
- if (full) FullManifestModule else PartialManifestModule,
- newTermName(constructor),
- List(tparg),
- args
- )
-
/** Make a synchronized block on 'monitor'. */
def mkSynchronized(monitor: Tree, body: Tree): Tree =
Apply(Select(monitor, Object_synchronized), List(body))
diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
index 9f361e5bcc..569cb4977b 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
@@ -44,7 +44,7 @@ abstract class TreeInfo extends reflect.internal.TreeInfo {
}
def isInterface(mods: HasFlags, body: List[Tree]) =
- mods.hasTraitFlag && (body forall isInterfaceMember)
+ mods.isTrait && (body forall isInterfaceMember)
def isAllowedInUniversalTrait(stat: Tree): Boolean = stat match {
case _: ValDef => false
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index de610df93e..59e36e86f6 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -13,6 +13,7 @@ import scala.reflect.internal.Flags.PARAM
import scala.reflect.internal.Flags.PARAMACCESSOR
import scala.reflect.internal.Flags.PRESUPER
import scala.reflect.internal.Flags.TRAIT
+import scala.compat.Platform.EOL
trait Trees extends reflect.internal.Trees { self: Global =>
@@ -33,30 +34,6 @@ trait Trees extends reflect.internal.Trees { self: Global =>
)
}
- class ValidatingPosAssigner extends PosAssigner {
- var pos: Position = _
- override def traverse(t: Tree) {
- if (t eq EmptyTree) ()
- else if (t.pos == NoPosition) super.traverse(t setPos pos)
- else if (globalPhase.id <= currentRun.picklerPhase.id) {
- // When we prune due to encountering a position, traverse the
- // pruned children so we can warn about those lacking positions.
- t.children foreach { c =>
- if ((c eq EmptyTree) || (c eq emptyValDef)) ()
- else if (c.pos == NoPosition) {
- reporter.warning(t.pos, " Positioned tree has unpositioned child in phase " + globalPhase)
- inform("parent: " + treeSymStatus(t))
- inform(" child: " + treeSymStatus(c) + "\n")
- }
- }
- }
- }
- }
-
- override protected[this] lazy val posAssigner: PosAssigner =
- if (settings.Yrangepos.value && settings.debug.value || settings.Yposdebug.value) new ValidatingPosAssigner
- else new DefaultPosAssigner
-
// --- additional cases --------------------------------------------------------
/** Only used during parsing */
case class Parens(args: List[Tree]) extends Tree
@@ -86,15 +63,6 @@ trait Trees extends reflect.internal.Trees { self: Global =>
/** emitted by typer, eliminated by refchecks */
case class TypeTreeWithDeferredRefCheck()(val check: () => TypeTree) extends TypTree
- /** Marks underlying reference to id as boxed.
- * @pre: 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 markBoxedReference.
- * It is eliminated in LambdaLift, where the boxing conversion takes place.
- */
- case class ReferenceToBoxed(idt: Ident) extends TermTree
-
// --- factory methods ----------------------------------------------------------
/** Generates a template with constructor corresponding to
@@ -120,7 +88,7 @@ trait Trees extends reflect.internal.Trees { self: Global =>
// create parameters for <init> as synthetic trees.
var vparamss1 =
vparamss map (vps => vps.map { vd =>
- atPos(focusPos(vd.pos)) {
+ atPos(vd.pos.focus) {
ValDef(
Modifiers(vd.mods.flags & (IMPLICIT | DEFAULTPARAM | BYNAMEPARAM) | PARAM | PARAMACCESSOR) withAnnotations vd.mods.annotations,
vd.name, vd.tpt.duplicate, vd.rhs.duplicate)
@@ -132,7 +100,7 @@ trait Trees extends reflect.internal.Trees { self: Global =>
// !!! I know "atPos in case" wasn't intentionally planted to
// add an air of mystery to this file, but it is the sort of
// comment which only its author could love.
- tpt = atPos(focusPos(vdef.pos))(TypeTree() setOriginal tpt setPos focusPos(tpt.pos)), // atPos in case
+ tpt = atPos(vdef.pos.focus)(TypeTree() setOriginal tpt setPos tpt.pos.focus), // atPos in case
rhs = EmptyTree
)
}
@@ -200,8 +168,6 @@ trait Trees extends reflect.internal.Trees { self: Global =>
traverser.traverse(qualifier)
case InjectDerivedValue(arg) =>
traverser.traverse(arg)
- case ReferenceToBoxed(idt) =>
- traverser.traverse(idt)
case TypeTreeWithDeferredRefCheck() =>
// (and rewrap the result? how to update the deferred check? would need to store wrapped tree instead of returning it from check)
case _ => super.xtraverse(traverser, tree)
@@ -211,7 +177,6 @@ trait Trees extends reflect.internal.Trees { self: Global =>
def DocDef(tree: Tree, comment: DocComment, definition: Tree): DocDef
def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type): SelectFromArray
def InjectDerivedValue(tree: Tree, arg: Tree): InjectDerivedValue
- def ReferenceToBoxed(tree: Tree, idt: Ident): ReferenceToBoxed
def TypeTreeWithDeferredRefCheck(tree: Tree): TypeTreeWithDeferredRefCheck
}
@@ -225,8 +190,6 @@ trait Trees extends reflect.internal.Trees { self: Global =>
new SelectFromArray(qualifier, selector, erasure).copyAttrs(tree)
def InjectDerivedValue(tree: Tree, arg: Tree) =
new InjectDerivedValue(arg)
- def ReferenceToBoxed(tree: Tree, idt: Ident) =
- new ReferenceToBoxed(idt).copyAttrs(tree)
def TypeTreeWithDeferredRefCheck(tree: Tree) = tree match {
case dc@TypeTreeWithDeferredRefCheck() => new TypeTreeWithDeferredRefCheck()(dc.check).copyAttrs(tree)
}
@@ -248,11 +211,6 @@ trait Trees extends reflect.internal.Trees { self: Global =>
if (arg0 == arg) => t
case _ => this.treeCopy.InjectDerivedValue(tree, arg)
}
- def ReferenceToBoxed(tree: Tree, idt: Ident) = tree match {
- case t @ ReferenceToBoxed(idt0)
- if (idt0 == idt) => t
- case _ => this.treeCopy.ReferenceToBoxed(tree, idt)
- }
def TypeTreeWithDeferredRefCheck(tree: Tree) = tree match {
case t @ TypeTreeWithDeferredRefCheck() => t
case _ => this.treeCopy.TypeTreeWithDeferredRefCheck(tree)
@@ -279,9 +237,6 @@ trait Trees extends reflect.internal.Trees { self: Global =>
case InjectDerivedValue(arg) =>
transformer.treeCopy.InjectDerivedValue(
tree, transformer.transform(arg))
- case ReferenceToBoxed(idt) =>
- transformer.treeCopy.ReferenceToBoxed(
- tree, transformer.transform(idt) match { case idt1: Ident => idt1 })
case TypeTreeWithDeferredRefCheck() =>
transformer.treeCopy.TypeTreeWithDeferredRefCheck(tree)
}
@@ -298,8 +253,8 @@ trait Trees extends reflect.internal.Trees { self: Global =>
// def resetAllAttrs[A<:Tree](x:A): A = { new ResetAttrsTraverser().traverse(x); x }
// def resetLocalAttrs[A<:Tree](x:A): A = { new ResetLocalAttrsTraverser().traverse(x); x }
- def resetAllAttrs[A<:Tree](x:A): A = new ResetAttrs(false).transform(x)
- def resetLocalAttrs[A<:Tree](x:A): A = new ResetAttrs(true).transform(x)
+ def resetAllAttrs[A <: Tree](x: A, leaveAlone: Tree => Boolean = null): A = new ResetAttrs(false, leaveAlone).transform(x)
+ def resetLocalAttrs[A <: Tree](x: A, leaveAlone: Tree => Boolean = null): A = new ResetAttrs(true, leaveAlone).transform(x)
/** A transformer which resets symbol and tpe fields of all nodes in a given tree,
* with special treatment of:
@@ -310,7 +265,7 @@ trait Trees extends reflect.internal.Trees { self: Global =>
*
* (bq:) This transformer has mutable state and should be discarded after use
*/
- private class ResetAttrs(localOnly: Boolean) {
+ private class ResetAttrs(localOnly: Boolean, leaveAlone: Tree => Boolean = null) {
val debug = settings.debug.value
val trace = scala.tools.nsc.util.trace when debug
@@ -330,6 +285,12 @@ trait Trees extends reflect.internal.Trees { self: Global =>
registerLocal(sym)
registerLocal(sym.sourceModule)
registerLocal(sym.moduleClass)
+ registerLocal(sym.companionClass)
+ registerLocal(sym.companionModule)
+ sym match {
+ case sym: TermSymbol => registerLocal(sym.referenced)
+ case _ => ;
+ }
}
}
@@ -337,10 +298,8 @@ trait Trees extends reflect.internal.Trees { self: Global =>
tree match {
case _: DefTree | Function(_, _) | Template(_, _, _) =>
markLocal(tree)
- case _ if tree.symbol.isInstanceOf[FreeVar] =>
- markLocal(tree)
case _ =>
- ;
+ tree
}
super.traverse(tree)
@@ -348,43 +307,48 @@ trait Trees extends reflect.internal.Trees { self: Global =>
}
class Transformer extends self.Transformer {
- override def transform(tree: Tree): Tree = super.transform {
- tree match {
- case tpt: TypeTree =>
- if (tpt.original != null) {
- transform(tpt.original)
- } else {
- if (tpt.tpe != null && (tpt.wasEmpty || (tpt.tpe exists (tp => locals contains tp.typeSymbol))))
- tpt.tpe = null
- tree
+ override def transform(tree: Tree): Tree = {
+ if (leaveAlone != null && leaveAlone(tree))
+ tree
+ else
+ super.transform {
+ tree match {
+ case tpt: TypeTree =>
+ if (tpt.original != null) {
+ transform(tpt.original)
+ } else {
+ if (tpt.tpe != null && (tpt.wasEmpty || (tpt.tpe exists (tp => locals contains tp.typeSymbol))))
+ tpt.tpe = null
+ tree
+ }
+ case TypeApply(fn, args) if args map transform exists (_.isEmpty) =>
+ transform(fn)
+ case This(_) if tree.symbol != null && tree.symbol.isPackageClass =>
+ tree
+ case EmptyTree =>
+ tree
+ case _ =>
+ if (tree.hasSymbol && (!localOnly || (locals contains tree.symbol)))
+ tree.symbol = NoSymbol
+ tree.tpe = null
+ tree
}
- case TypeApply(fn, args) if args map transform exists (_.isEmpty) =>
- transform(fn)
- case This(_) if tree.symbol != null && tree.symbol.isPackageClass =>
- tree
- case EmptyTree =>
- tree
- case _ =>
- if (tree.hasSymbol && (!localOnly || (locals contains tree.symbol)))
- tree.symbol = NoSymbol
- tree.tpe = null
- tree
+ }
}
- }
}
def transform[T <: Tree](x: T): T = {
- new MarkLocals().traverse(x)
+ if (localOnly)
+ new MarkLocals().traverse(x)
- if (debug) {
+ if (localOnly && debug) {
assert(locals.size == orderedLocals.size)
- val eoln = System.getProperty("line.separator")
- val msg = orderedLocals.toList filter {_ != NoSymbol} map {" " + _} mkString eoln
+ val msg = orderedLocals.toList filter {_ != NoSymbol} map {" " + _} mkString EOL
trace("locals (%d total): %n".format(orderedLocals.size))(msg)
}
val x1 = new Transformer().transform(x)
- assert(x.getClass isInstance x1)
+ assert(x.getClass isInstance x1, x1.getClass)
x1.asInstanceOf[T]
}
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index eda75ae187..978640b4a5 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -249,7 +249,7 @@ self =>
final val InBlock = 1
final val InTemplate = 2
- lazy val ScalaValueClassNames: Set[Name] = definitions.scalaValueClassesSet map (_.name)
+ lazy val ScalaValueClassNames = tpnme.AnyVal :: definitions.ScalaValueClasses.map(_.name)
import nme.raw
@@ -1772,7 +1772,23 @@ self =>
* }}}
*/
def pattern2(): Tree = {
+ val nameOffset = in.offset
+ def warnIfMacro(tree: Tree): Unit = {
+ def check(name: Name): Unit = if (name.toString == nme.MACROkw.toString)
+ warning(nameOffset, "in future versions of Scala \"macro\" will be a keyword. consider using a different name.")
+ tree match {
+ case _: BackQuotedIdent =>
+ ;
+ case Ident(name) =>
+ check(name)
+ case _ =>
+ ;
+ }
+ }
+
val p = pattern3()
+ warnIfMacro(p)
+
if (in.token != AT) p
else p match {
case Ident(nme.WILDCARD) =>
@@ -2422,10 +2438,10 @@ self =>
*/
/** {{{
- * FunDef ::= FunSig `:' Type `=' Expr
- * | FunSig [nl] `{' Block `}'
- * | this ParamClause ParamClauses (`=' ConstrExpr | [nl] ConstrBlock)
- * | `macro' FunSig [`:' Type] `=' Expr
+ * FunDef ::= FunSig [`:' Type] `=' [`macro'] Expr
+ * | FunSig [nl] `{' Block `}'
+ * | `this' ParamClause ParamClauses
+ * (`=' ConstrExpr | [nl] ConstrBlock)
* FunDcl ::= FunSig [`:' Type]
* FunSig ::= id [FunTypeParamClause] ParamClauses
* }}}
@@ -2445,18 +2461,16 @@ self =>
}
else {
val nameOffset = in.offset
+ val isBackquoted = in.token == BACKQUOTED_IDENT
val name = ident()
- if (name == nme.macro_ && isIdent && settings.Xmacros.value)
- funDefRest(start, in.offset, mods | Flags.MACRO, ident())
- else
- funDefRest(start, nameOffset, mods, name)
+ if (name.toString == nme.MACROkw.toString && !isBackquoted)
+ warning(nameOffset, "in future versions of Scala \"macro\" will be a keyword. consider using a different name.")
+ funDefRest(start, nameOffset, mods, name)
}
}
def funDefRest(start: Int, nameOffset: Int, mods: Modifiers, name: Name): Tree = {
val result = atPos(start, if (name.toTermName == nme.ERROR) start else nameOffset) {
- val isMacro = mods hasFlag Flags.MACRO
- val isTypeMacro = isMacro && name.isTypeName
var newmods = mods
// contextBoundBuf is for context bounded type parameters of the form
// [T : B] or [T : => B]; it contains the equivalent implicit parameter type,
@@ -2464,12 +2478,10 @@ self =>
val contextBoundBuf = new ListBuffer[Tree]
val tparams = typeParamClauseOpt(name, contextBoundBuf)
val vparamss = paramClauses(name, contextBoundBuf.toList, false)
- if (!isMacro) newLineOptWhenFollowedBy(LBRACE)
- var restype = if (isTypeMacro) TypeTree() else fromWithinReturnType(typedOpt())
- val rhs =
- if (isMacro)
- equalsExpr()
- else if (isStatSep || in.token == RBRACE) {
+ newLineOptWhenFollowedBy(LBRACE)
+ var restype = fromWithinReturnType(typedOpt())
+ val rhs =
+ if (isStatSep || in.token == RBRACE) {
if (restype.isEmpty) restype = scalaUnitConstr
newmods |= Flags.DEFERRED
EmptyTree
@@ -2477,10 +2489,12 @@ self =>
restype = scalaUnitConstr
blockExpr()
} else {
- if (name == nme.macro_ && isIdent && in.token != EQUALS) {
- warning("this syntactically invalid code resembles a macro definition. have you forgotten to enable -Xmacros?")
+ accept(EQUALS)
+ if (settings.Xmacros.value && in.token == MACRO) {
+ in.nextToken()
+ newmods |= Flags.MACRO
}
- equalsExpr()
+ expr()
}
DefDef(newmods, name, tparams, vparamss, restype, rhs)
}
@@ -2530,7 +2544,7 @@ self =>
/** {{{
* TypeDef ::= type Id [TypeParamClause] `=' Type
- * | `macro' FunSig `=' Expr
+ * | FunSig `=' Expr
* TypeDcl ::= type Id [TypeParamClause] TypeBounds
* }}}
*/
@@ -2538,22 +2552,22 @@ self =>
in.nextToken()
newLinesOpt()
atPos(start, in.offset) {
+ val nameOffset = in.offset
+ val isBackquoted = in.token == BACKQUOTED_IDENT
val name = identForType()
- if (name == nme.macro_.toTypeName && isIdent && settings.Xmacros.value) {
- funDefRest(start, in.offset, mods | Flags.MACRO, identForType())
- } else {
- // @M! a type alias as well as an abstract type may declare type parameters
- val tparams = typeParamClauseOpt(name, null)
- in.token match {
- case EQUALS =>
- in.nextToken()
- TypeDef(mods, name, tparams, typ())
- case SUPERTYPE | SUBTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE =>
- TypeDef(mods | Flags.DEFERRED, name, tparams, typeBounds())
- case _ =>
- syntaxErrorOrIncomplete("`=', `>:', or `<:' expected", true)
- EmptyTree
- }
+ if (name.toString == nme.MACROkw.toString && !isBackquoted)
+ warning(nameOffset, "in future versions of Scala \"macro\" will be a keyword. consider using a different name.")
+ // @M! a type alias as well as an abstract type may declare type parameters
+ val tparams = typeParamClauseOpt(name, null)
+ in.token match {
+ case EQUALS =>
+ in.nextToken()
+ TypeDef(mods, name, tparams, typ())
+ case SUPERTYPE | SUBTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE =>
+ TypeDef(mods | Flags.DEFERRED, name, tparams, typeBounds())
+ case _ =>
+ syntaxErrorOrIncomplete("`=', `>:', or `<:' expected", true)
+ EmptyTree
}
}
}
@@ -2600,8 +2614,10 @@ self =>
def classDef(start: Int, mods: Modifiers): ClassDef = {
in.nextToken
val nameOffset = in.offset
+ val isBackquoted = in.token == BACKQUOTED_IDENT
val name = identForType()
- def isTrait = mods.hasTraitFlag
+ if (name.toString == nme.MACROkw.toString && !isBackquoted)
+ warning(nameOffset, "in future versions of Scala \"macro\" will be a keyword. consider using a different name.")
atPos(start, if (name == tpnme.ERROR) start else nameOffset) {
savingClassContextBounds {
@@ -2609,16 +2625,16 @@ self =>
val tparams = typeParamClauseOpt(name, contextBoundBuf)
classContextBounds = contextBoundBuf.toList
val tstart = in.offset :: classContextBounds.map(_.pos.startOrPoint) min;
- if (!classContextBounds.isEmpty && isTrait) {
+ if (!classContextBounds.isEmpty && mods.isTrait) {
syntaxError("traits cannot have type parameters with context bounds `: ...' nor view bounds `<% ...'", false)
classContextBounds = List()
}
val constrAnnots = constructorAnnotations()
val (constrMods, vparamss) =
- if (isTrait) (Modifiers(Flags.TRAIT), List())
+ if (mods.isTrait) (Modifiers(Flags.TRAIT), List())
else (accessModifierOpt(), paramClauses(name, classContextBounds, mods.isCase))
var mods1 = mods
- if (isTrait) {
+ if (mods.isTrait) {
if (settings.YvirtClasses && in.token == SUBTYPE) mods1 |= Flags.DEFERRED
} else if (in.token == SUBTYPE) {
syntaxError("classes are not allowed to be virtual", false)
@@ -2642,7 +2658,10 @@ self =>
def objectDef(start: Int, mods: Modifiers): ModuleDef = {
in.nextToken
val nameOffset = in.offset
+ val isBackquoted = in.token == BACKQUOTED_IDENT
val name = ident()
+ if (name.toString == nme.MACROkw.toString && !isBackquoted)
+ warning(nameOffset, "in future versions of Scala \"macro\" will be a keyword. consider using a different name.")
val tstart = in.offset
atPos(start, if (name == nme.ERROR) start else nameOffset) {
val mods1 = if (in.token == SUBTYPE) mods | Flags.DEFERRED else mods
@@ -2710,7 +2729,7 @@ self =>
}
def isInterface(mods: Modifiers, body: List[Tree]): Boolean =
- mods.hasTraitFlag && (body forall treeInfo.isInterfaceMember)
+ mods.isTrait && (body forall treeInfo.isInterfaceMember)
/** {{{
* ClassTemplateOpt ::= `extends' ClassTemplate | [[`extends'] TemplateBody]
@@ -2720,9 +2739,9 @@ self =>
*/
def templateOpt(mods: Modifiers, name: Name, constrMods: Modifiers, vparamss: List[List[ValDef]], tstart: Int): Template = {
val (parents0, argss, self, body) = (
- if (in.token == EXTENDS || in.token == SUBTYPE && mods.hasTraitFlag) {
+ if (in.token == EXTENDS || in.token == SUBTYPE && mods.isTrait) {
in.nextToken()
- template(mods.hasTraitFlag)
+ template(mods.isTrait)
}
else {
newLineOptWhenFollowedBy(LBRACE)
@@ -2745,9 +2764,8 @@ self =>
val tstart0 = if (body.isEmpty && in.lastOffset < tstart) in.lastOffset else tstart
atPos(tstart0) {
- // [Martin to Paul: This needs to be refined. We should only include the 9 primitive classes,
- // not any other value classes that happen to be defined in the Scala package.
- if (inScalaRootPackage && (name == tpnme.AnyVal || (ScalaValueClassNames contains name)))
+ // Exclude only the 9 primitives plus AnyVal.
+ if (inScalaRootPackage && ScalaValueClassNames.contains(name))
Template(parents0, self, anyvalConstructor :: body)
else
Template(anyrefParents, self, constrMods, vparamss, argss, body, o2p(tstart))
@@ -2821,7 +2839,25 @@ self =>
* }}}
*/
def packaging(start: Int): Tree = {
+ val nameOffset = in.offset
+ def warnIfMacro(tree: Tree): Unit = {
+ def check(name: Name): Unit = if (name.toString == nme.MACROkw.toString)
+ warning(nameOffset, "in future versions of Scala \"macro\" will be a keyword. consider using a different name.")
+ tree match {
+ case _: BackQuotedIdent =>
+ ;
+ case Ident(name) =>
+ check(name)
+ case Select(qual, name) =>
+ warnIfMacro(qual)
+ check(name)
+ case _ =>
+ ;
+ }
+ }
+
val pkg = pkgQualId()
+ warnIfMacro(pkg)
val stats = inBracesOrNil(topStatSeq())
makePackaging(start, pkg, stats)
}
@@ -3023,8 +3059,29 @@ self =>
ts ++= topStatSeq()
}
} else {
+ val nameOffset = in.offset
+ def warnIfMacro(tree: Tree): Unit = {
+ def check(name: Name): Unit = if (name.toString == nme.MACROkw.toString)
+ warning(nameOffset, "in future versions of Scala \"macro\" will be a keyword. consider using a different name.")
+ tree match {
+ // [Eugene] pkgQualId never returns BackQuotedIdents
+ // this means that we'll get spurious warnings even if we wrap macro package name in backquotes
+ case _: BackQuotedIdent =>
+ ;
+ case Ident(name) =>
+ check(name)
+ case Select(qual, name) =>
+ warnIfMacro(qual)
+ check(name)
+ case _ =>
+ ;
+ }
+ }
+
in.flushDoc
val pkg = pkgQualId()
+ warnIfMacro(pkg)
+
if (in.token == EOF) {
ts += makePackaging(start, pkg, List())
} else if (isStatSep) {
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index 2895d02dfe..81d81a4fb7 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -1125,7 +1125,8 @@ trait Scanners extends ScannersCommon {
nme.SUPERTYPEkw -> SUPERTYPE,
nme.HASHkw -> HASH,
nme.ATkw -> AT
- )
+ ) ++
+ (if (settings.Xmacros.value) List(nme.MACROkw -> MACRO) else List())
private var kwOffset: Int = -1
private val kwArray: Array[Int] = {
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala
index fb4daefd57..e17bbf5e46 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala
@@ -110,6 +110,7 @@ object Tokens extends Tokens {
final val MATCH = 58
final val FORSOME = 59
final val LAZY = 61
+ final val MACRO = 62
def isKeyword(code: Int) =
code >= IF && code <= LAZY
diff --git a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
index 27df45b563..314a3b45a0 100644
--- a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
+++ b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
@@ -38,10 +38,10 @@ trait JavaPlatform extends Platform {
genJVM // generate .class files
) ++ depAnalysisPhase
- lazy val externalEquals = getMember(BoxesRunTimeClass, nme.equals_)
- lazy val externalEqualsNumNum = getMember(BoxesRunTimeClass, nme.equalsNumNum)
- lazy val externalEqualsNumChar = getMember(BoxesRunTimeClass, nme.equalsNumChar)
- lazy val externalEqualsNumObject = getMember(BoxesRunTimeClass, nme.equalsNumObject)
+ lazy val externalEquals = getDecl(BoxesRunTimeClass, nme.equals_)
+ lazy val externalEqualsNumNum = getDecl(BoxesRunTimeClass, nme.equalsNumNum)
+ lazy val externalEqualsNumChar = getDecl(BoxesRunTimeClass, nme.equalsNumChar)
+ lazy val externalEqualsNumObject = getDecl(BoxesRunTimeClass, nme.equalsNumObject)
/** We could get away with excluding BoxedBooleanClass for the
* purpose of equality testing since it need not compare equal
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 8e568eca79..ec303d76ee 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -1533,7 +1533,7 @@ abstract class GenICode extends SubComponent {
*/
def genEqEqPrimitive(l: Tree, r: Tree, ctx: Context)(thenCtx: Context, elseCtx: Context): Unit = {
def getTempLocal = ctx.method.lookupLocal(nme.EQEQ_LOCAL_VAR) getOrElse {
- ctx.makeLocal(l.pos, AnyRefClass.typeConstructor, nme.EQEQ_LOCAL_VAR)
+ ctx.makeLocal(l.pos, AnyRefClass.tpe, nme.EQEQ_LOCAL_VAR)
}
/** True if the equality comparison is between values that require the use of the rich equality
diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
index 2ff0c1926c..7ad7cadd92 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
@@ -142,7 +142,7 @@ trait TypeKinds { self: ICodes =>
def lub0(tk1: TypeKind, tk2: TypeKind): Type = beforeUncurry {
import definitions._
val tp = global.lub(List(tk1.toType, tk2.toType))
- val (front, rest) = tp.parents span (_.typeSymbol.hasTraitFlag)
+ val (front, rest) = tp.parents span (_.typeSymbol.isTrait)
if (front.isEmpty || rest.isEmpty || rest.head.typeSymbol == ObjectClass) tp
else rest.head
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index 7b7135d180..c04be1721e 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -651,7 +651,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
case StringTag =>
buf put 's'.toByte
buf putShort cpool.addUtf8(const.stringValue).toShort
- case ClassTag =>
+ case ClazzTag =>
buf put 'c'.toByte
buf putShort cpool.addUtf8(javaType(const.typeValue).getSignature()).toShort
case EnumTag =>
@@ -1022,7 +1022,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
serialVUID foreach { value =>
import Flags._, definitions._
val fieldName = "serialVersionUID"
- val fieldSymbol = clasz.symbol.newValue(newTermName(fieldName), NoPosition, STATIC | FINAL) setInfo longType
+ val fieldSymbol = clasz.symbol.newValue(newTermName(fieldName), NoPosition, STATIC | FINAL) setInfo LongClass.tpe
clasz addField new IField(fieldSymbol)
lastBlock emit CONSTANT(Constant(value))
lastBlock emit STORE_FIELD(fieldSymbol, true)
@@ -1281,7 +1281,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
val jname = javaName(method)
val jtype = javaType(method).asInstanceOf[JMethodType]
- def debugMsg(invoke: String) {
+ def dbg(invoke: String) {
debuglog("%s %s %s.%s:%s".format(invoke, receiver.accessString, jowner, jname, jtype))
}
@@ -1299,14 +1299,14 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
}
style match {
- case Static(true) => jcode.emitINVOKESPECIAL (jowner, jname, jtype) ; debugMsg("invokespecial")
- case Static(false) => jcode.emitINVOKESTATIC (jowner, jname, jtype) ; debugMsg("invokestatic")
- case Dynamic if isInterfaceCall(receiver) => jcode.emitINVOKEINTERFACE(jowner, jname, jtype) ; debugMsg("invokinterface")
- case Dynamic => jcode.emitINVOKEVIRTUAL (jowner, jname, jtype) ; debugMsg("invokevirtual")
+ case Static(true) => dbg("invokespecial"); jcode.emitINVOKESPECIAL(jowner, jname, jtype)
+ case Static(false) => dbg("invokestatic"); jcode.emitINVOKESTATIC(jowner, jname, jtype)
+ case Dynamic if isInterfaceCall(receiver) => dbg("invokinterface"); jcode.emitINVOKEINTERFACE(jowner, jname, jtype)
+ case Dynamic => dbg("invokevirtual"); jcode.emitINVOKEVIRTUAL(jowner, jname, jtype)
case SuperCall(_) =>
+ dbg("invokespecial")
jcode.emitINVOKESPECIAL(jowner, jname, jtype)
initModule()
- debugMsg("invokespecial")
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala
index b74981b999..807a3dd0bb 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala
@@ -121,7 +121,7 @@ trait GenJVMUtil {
case DoubleTag => jcode emitPUSH const.doubleValue
case StringTag => jcode emitPUSH const.stringValue
case NullTag => jcode.emitACONST_NULL()
- case ClassTag =>
+ case ClazzTag =>
val kind = toTypeKind(const.typeValue)
val toPush =
if (kind.isValueType) classLiteral(kind)
diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
index 2fb615f893..98c1fc2f63 100644
--- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
+++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
@@ -365,7 +365,7 @@ abstract class GenMSIL extends SubComponent {
arr.foreach(emitConst)
}
- // TODO: other Tags: NoTag, UnitTag, ClassTag, EnumTag, ArrayTag ???
+ // TODO: other Tags: NoTag, UnitTag, ClazzTag, EnumTag, ArrayTag ???
case _ => abort("could not handle attribute argument: " + const)
}
@@ -388,7 +388,7 @@ abstract class GenMSIL extends SubComponent {
case DoubleTag => buf.put(0x0d.toByte)
case StringTag => buf.put(0x0e.toByte)
- // TODO: other Tags: NoTag, UnitTag, ClassTag, EnumTag ???
+ // TODO: other Tags: NoTag, UnitTag, ClazzTag, EnumTag ???
// ArrayTag falls in here
case _ => abort("could not handle attribute argument: " + c)
@@ -968,7 +968,7 @@ abstract class GenMSIL extends SubComponent {
case DoubleTag => mcode.Emit(OpCodes.Ldc_R8, const.doubleValue)
case StringTag => mcode.Emit(OpCodes.Ldstr, const.stringValue)
case NullTag => mcode.Emit(OpCodes.Ldnull)
- case ClassTag =>
+ case ClazzTag =>
mcode.Emit(OpCodes.Ldtoken, msilType(const.typeValue))
mcode.Emit(OpCodes.Call, TYPE_FROM_HANDLE)
case _ => abort("Unknown constant value: " + const)
diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
index 702d643fb4..670c9bbb3b 100644
--- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
@@ -474,7 +474,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
if (bSym == definitions.Object_synchronized) {
val cSymInfo = (bSym.info: @unchecked) match {
case PolyType(ts, MethodType(List(bp), mt)) =>
- val cp = bp.cloneSymbol.setInfo(appliedType(definitions.ByNameParamClass.typeConstructor, List(bp.info)))
+ val cp = bp.cloneSymbol.setInfo(definitions.byNameType(bp.info))
PolyType(ts, MethodType(List(cp), mt))
}
bSym.cloneSymbol.setInfo(cSymInfo)
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index 4cf31cc576..7233b11701 100644
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -434,6 +434,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
private def newRunnerThread(): Thread = {
threadId += 1
compileRunner = new PresentationCompilerThread(this, projectName)
+ compileRunner.setDaemon(true)
compileRunner.start()
compileRunner
}
@@ -957,7 +958,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
if (ownerTpe.isErroneous) List()
else new ImplicitSearch(
tree, functionType(List(ownerTpe), AnyClass.tpe), isView = true,
- context.makeImplicit(reportAmbiguousErrors = false)).allImplicits
+ context0 = context.makeImplicit(reportAmbiguousErrors = false)).allImplicits
for (view <- applicableViews) {
val vtree = viewApply(view)
val vpre = stabilizedType(vtree)
diff --git a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala
index 88e3827403..72e5ee42ed 100644
--- a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala
+++ b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala
@@ -6,7 +6,7 @@ package scala.tools.nsc
package interactive
import ast.Trees
-import symtab.Positions
+import ast.Positions
import scala.tools.nsc.util.{SourceFile, Position, RangePosition, NoPosition, WorkScheduler}
import scala.collection.mutable.ListBuffer
diff --git a/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala b/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala
index 68c8f2fdb8..a2ce8439de 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala
@@ -124,7 +124,7 @@ trait ExprTyper {
val decls = sym.tpe.decls.toList filterNot (x => x.isConstructor || x.isPrivate || (x.name.toString contains "$"))
repltrace("decls: " + decls)
if (decls.isEmpty) NoType
- else typeCleanser(sym, decls.last.name)
+ else cleanMemberDecl(sym, decls.last.name)
}
case _ =>
NoType
diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
index e1ea69842f..108d4377a8 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
@@ -815,7 +815,10 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
interpretStartingWith(intp.mostRecentVar + code)
}
else {
- def runCompletion = in.completion execute code map (intp bindValue _)
+ def runCompletion =
+ try in.completion execute code map (intp bindValue _)
+ catch { case ex: Exception => None }
+
/** Due to my accidentally letting file completion execution sneak ahead
* of actual parsing this now operates in such a way that the scala
* interpretation always wins. However to avoid losing useful file
@@ -881,6 +884,9 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
case x => x
}
}
+ // Bind intp somewhere out of the regular namespace where
+ // we can get at it in generated code.
+ addThunk(intp.quietBind("$intp" -> intp))
loadFiles(settings)
// it is broken on startup; go ahead and exit
diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
index 9a12bc1471..c0f7d8412a 100644
--- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
@@ -13,6 +13,7 @@ import scala.sys.BooleanProp
import io.VirtualDirectory
import scala.tools.nsc.io.AbstractFile
import reporters._
+import reporters.{Reporter => NscReporter}
import symtab.Flags
import scala.reflect.internal.Names
import scala.tools.util.PathResolver
@@ -93,6 +94,11 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
private var _lineManager: Line.Manager = null // logic for individual lines
private val _compiler: Global = newCompiler(settings, reporter) // our private compiler
+ private val nextReqId = {
+ var counter = 0
+ () => { counter += 1 ; counter }
+ }
+
def compilerClasspath: Seq[URL] = (
if (isInitializeComplete) global.classPath.asURLs
else new PathResolver(settings).result.asURLs // the compiler's classpath
@@ -269,7 +275,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
protected def createLineManager(classLoader: ClassLoader): Line.Manager = new Line.Manager(classLoader)
/** Instantiate a compiler. Overridable. */
- protected def newCompiler(settings: Settings, reporter: Reporter) = {
+ protected def newCompiler(settings: Settings, reporter: NscReporter) = {
settings.outputDirs setSingleOutput virtualDirectory
settings.exposeEmptyPackage.value = true
@@ -335,7 +341,14 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
def getInterpreterClassLoader() = classLoader
// Set the current Java "context" class loader to this interpreter's class loader
- def setContextClassLoader() = classLoader.setAsContext()
+ def setContextClassLoader() = {
+ classLoader.setAsContext()
+
+ // this is risky, but it's our only possibility to make default reflexive mirror to work with REPL
+ // so far we have only used the default mirror to create a few manifests for the compiler
+ // so it shouldn't be in conflict with our classloader, especially since it respects its parent
+ scala.reflect.mirror.classLoader = classLoader
+ }
/** Given a simple repl-defined name, returns the real name of
* the class representing it, e.g. for "Bippy" it may return
@@ -457,7 +470,10 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
/** Build a request from the user. `trees` is `line` after being parsed.
*/
- private def buildRequest(line: String, trees: List[Tree]): Request = new Request(line, trees)
+ private def buildRequest(line: String, trees: List[Tree]): Request = {
+ executingRequest = new Request(line, trees)
+ executingRequest
+ }
// rewriting "5 // foo" to "val x = { 5 // foo }" creates broken code because
// the close brace is commented out. Strip single-line comments.
@@ -556,17 +572,10 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
Right(buildRequest(line, trees))
}
- def typeCleanser(sym: Symbol, memberName: Name): Type = {
- // the types are all =>T; remove the =>
- val tp1 = afterTyper(sym.info.nonPrivateDecl(memberName).tpe match {
- case NullaryMethodType(tp) => tp
- case tp => tp
- })
- // normalize non-public types so we don't see protected aliases like Self
- afterTyper(tp1 match {
- case TypeRef(_, sym, _) if !sym.isPublic => tp1.normalize
- case tp => tp
- })
+ // normalize non-public types so we don't see protected aliases like Self
+ def normalizeNonPublic(tp: Type) = tp match {
+ case TypeRef(_, sym, _) if sym.isAliasType && !sym.isPublic => tp.normalize
+ case _ => tp
}
/**
@@ -623,7 +632,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
* @param value the object value to bind to it
* @return an indication of whether the binding succeeded
*/
- def bind(name: String, boundType: String, value: Any): IR.Result = {
+ def bind(name: String, boundType: String, value: Any, modifiers: List[String] = Nil): IR.Result = {
val bindRep = new ReadEvalPrint()
val run = bindRep.compile("""
|object %s {
@@ -639,7 +648,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
IR.Error
case Right(_) =>
- val line = "val %s = %s.value".format(name, bindRep.evalPath)
+ val line = "%sval %s = %s.value".format(modifiers map (_ + " ") mkString, name, bindRep.evalPath)
repldbg("Interpreting: " + line)
interpret(line)
}
@@ -824,7 +833,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
case xs => sys.error("Internal error: eval object " + evalClass + ", " + xs.mkString("\n", "\n", ""))
}
private def compileAndSaveRun(label: String, code: String) = {
- showCodeIfDebugging(packaged(code))
+ showCodeIfDebugging(code)
val (success, run) = compileSourcesKeepingRun(new BatchSourceFile(label, packaged(code)))
lastRun = run
success
@@ -834,6 +843,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
/** One line of code submitted by the user for interpretation */
// private
class Request(val line: String, val trees: List[Tree]) {
+ val reqId = nextReqId()
val lineRep = new ReadEvalPrint()
private var _originalLine: String = null
@@ -882,14 +892,31 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
/** generate the source code for the object that computes this request */
private object ObjectSourceCode extends CodeAssembler[MemberHandler] {
+ def path = pathToTerm("$intp")
+ def envLines = {
+ if (!isReplPower) Nil // power mode only for now
+ // $intp is not bound; punt, but include the line.
+ else if (path == "$intp") List(
+ "def $line = " + tquoted(originalLine),
+ "def $trees = Nil"
+ )
+ else List(
+ "def $line = " + tquoted(originalLine),
+ "def $req = %s.requestForReqId(%s).orNull".format(path, reqId),
+ "def $trees = if ($req eq null) Nil else $req.trees".format(lineRep.readName, path, reqId)
+ )
+ }
+
val preamble = """
|object %s {
- |%s%s
- """.stripMargin.format(lineRep.readName, importsPreamble, indentCode(toCompute))
+ |%s%s%s
+ """.stripMargin.format(lineRep.readName, envLines.map(" " + _ + ";\n").mkString, importsPreamble, indentCode(toCompute))
val postamble = importsTrailer + "\n}"
val generate = (m: MemberHandler) => m extraCodeToEvaluate Request.this
}
+ def tquoted(s: String) = "\"\"\"" + s + "\"\"\""
+
private object ResultObjectSourceCode extends CodeAssembler[MemberHandler] {
/** We only want to generate this code when the result
* is a value which can be referred to as-is.
@@ -959,8 +986,9 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
def lookupTypeOf(name: Name) = typeOf.getOrElse(name, typeOf(global.encode(name.toString)))
def simpleNameOfType(name: TypeName) = (compilerTypeOf get name) map (_.typeSymbol.simpleName)
- private def typeMap[T](f: Type => T): Map[Name, T] =
- termNames ++ typeNames map (x => x -> f(typeCleanser(resultSymbol, x))) toMap
+ private def typeMap[T](f: Type => T): Map[Name, T] = {
+ termNames ++ typeNames map (x => x -> f(cleanMemberDecl(resultSymbol, x))) toMap
+ }
/** Types of variables defined by this request. */
lazy val compilerTypeOf = typeMap[Type](x => x)
@@ -1023,6 +1051,13 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
getOrElse Nil
)
+ def treesForRequestId(id: Int): List[Tree] =
+ requestForReqId(id).toList flatMap (_.trees)
+
+ def requestForReqId(id: Int): Option[Request] =
+ if (executingRequest != null && executingRequest.reqId == id) Some(executingRequest)
+ else prevRequests find (_.reqId == id)
+
def requestForName(name: Name): Option[Request] = {
assert(definedNameMap != null, "definedNameMap is null")
definedNameMap get name
@@ -1072,6 +1107,14 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
else NoType
}
}
+ def cleanMemberDecl(owner: Symbol, member: Name): Type = afterTyper {
+ normalizeNonPublic {
+ owner.info.nonPrivateDecl(member).tpe match {
+ case NullaryMethodType(tp) => tp
+ case tp => tp
+ }
+ }
+ }
object replTokens extends {
val global: imain.global.type = imain.global
@@ -1118,15 +1161,18 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
def apply[T: ClassManifest] : Symbol = apply(classManifest[T].erasure.getName)
/** the previous requests this interpreter has processed */
- private lazy val prevRequests = mutable.ListBuffer[Request]()
- private lazy val referencedNameMap = mutable.Map[Name, Request]()
- private lazy val definedNameMap = mutable.Map[Name, Request]()
- private lazy val directlyBoundNames = mutable.Set[Name]()
- protected def prevRequestList = prevRequests.toList
- private def allHandlers = prevRequestList flatMap (_.handlers)
- def allSeenTypes = prevRequestList flatMap (_.typeOf.values.toList) distinct
- def allImplicits = allHandlers filter (_.definesImplicit) flatMap (_.definedNames)
- def importHandlers = allHandlers collect { case x: ImportHandler => x }
+ private var executingRequest: Request = _
+ private val prevRequests = mutable.ListBuffer[Request]()
+ private val referencedNameMap = mutable.Map[Name, Request]()
+ private val definedNameMap = mutable.Map[Name, Request]()
+ private val directlyBoundNames = mutable.Set[Name]()
+
+ private def allHandlers = prevRequestList flatMap (_.handlers)
+ def lastRequest = if (prevRequests.isEmpty) null else prevRequests.last
+ def prevRequestList = prevRequests.toList
+ def allSeenTypes = prevRequestList flatMap (_.typeOf.values.toList) distinct
+ def allImplicits = allHandlers filter (_.definesImplicit) flatMap (_.definedNames)
+ def importHandlers = allHandlers collect { case x: ImportHandler => x }
def visibleTermNames: List[Name] = definedTerms ++ importedTerms distinct
diff --git a/src/compiler/scala/tools/nsc/interpreter/Naming.scala b/src/compiler/scala/tools/nsc/interpreter/Naming.scala
index 19266442cb..c3f51c74ec 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Naming.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Naming.scala
@@ -41,10 +41,10 @@ trait Naming {
private def removeIWPackages(s: String) = s.replaceAll("""\$iw[$.]""", "")
trait SessionNames {
- // All values are configurable by passing e.g. -Dscala.repl.naming.read=XXX
+ // All values are configurable by passing e.g. -Dscala.repl.name.read=XXX
final def propOr(name: String): String = propOr(name, "$" + name)
final def propOr(name: String, default: String): String =
- sys.props.getOrElse("scala.repl.naming." + name, default)
+ sys.props.getOrElse("scala.repl.name." + name, default)
// Prefixes used in repl machinery. Default to $line, $read, etc.
def line = propOr("line")
diff --git a/src/compiler/scala/tools/nsc/interpreter/Power.scala b/src/compiler/scala/tools/nsc/interpreter/Power.scala
index 14876425f4..cc06100f5f 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Power.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Power.scala
@@ -6,7 +6,6 @@
package scala.tools.nsc
package interpreter
-import scala.reflect.AnyValManifest
import scala.collection.{ mutable, immutable }
import scala.util.matching.Regex
import scala.tools.nsc.util.{ BatchSourceFile }
diff --git a/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala b/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala
index a68392f0fb..e293c0fed9 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala
@@ -31,6 +31,7 @@ class StdReplVals(final val r: ILoop) extends ReplVals {
power.unit("").asInstanceOf[analyzer.global.CompilationUnit]
)
)
+ def lastRequest = intp.lastRequest
final lazy val replImplicits = new power.Implicits2 {
import intp.global._
@@ -57,17 +58,17 @@ object ReplVals {
* I have this forwarder which widens the type and then cast the result back
* to the dependent type.
*/
- def manifestToType(m: OptManifest[_]): Global#Type =
+ def manifestToType(m: Manifest[_]): Global#Type =
definitions.manifestToType(m)
class AppliedTypeFromManifests(sym: Symbol) {
def apply[M](implicit m1: Manifest[M]): Type =
if (sym eq NoSymbol) NoType
- else appliedType(sym.typeConstructor, List(m1) map (x => manifestToType(x).asInstanceOf[Type]))
+ else appliedType(sym, manifestToType(m1).asInstanceOf[Type])
def apply[M1, M2](implicit m1: Manifest[M1], m2: Manifest[M2]): Type =
if (sym eq NoSymbol) NoType
- else appliedType(sym.typeConstructor, List(m1, m2) map (x => manifestToType(x).asInstanceOf[Type]))
+ else appliedType(sym, manifestToType(m1).asInstanceOf[Type], manifestToType(m2).asInstanceOf[Type])
}
(sym: Symbol) => new AppliedTypeFromManifests(sym)
diff --git a/src/compiler/scala/tools/nsc/interpreter/RichClass.scala b/src/compiler/scala/tools/nsc/interpreter/RichClass.scala
index 5edc8fd202..59a7b9b5d2 100644
--- a/src/compiler/scala/tools/nsc/interpreter/RichClass.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/RichClass.scala
@@ -7,7 +7,7 @@ package scala.tools.nsc
package interpreter
class RichClass[T](val clazz: Class[T]) {
- def toManifest: Manifest[T] = Manifest.classType(clazz)
+ def toManifest: Manifest[T] = Manifest[T](ClassManifest[T](clazz).tpe)
def toTypeString: String = TypeStrings.fromClazz(clazz)
// Sadly isAnonymousClass does not return true for scala anonymous
diff --git a/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala b/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala
index 6b56d881fc..872ac00bfd 100644
--- a/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala
@@ -10,6 +10,7 @@ import java.lang.{ reflect => r }
import r.TypeVariable
import scala.reflect.NameTransformer
import NameTransformer._
+import scala.reflect.{mirror => rm}
/** Logic for turning a type into a String. The goal is to be
* able to take some arbitrary object 'x' and obtain the most precise
@@ -72,8 +73,12 @@ trait TypeStrings {
brackets(clazz.getTypeParameters map tvarString: _*)
}
- private def tparamString[T: Manifest] : String =
- brackets(manifest[T].typeArguments map (m => tvarString(List(m.erasure))): _*)
+ private def tparamString[T: Manifest] : String = {
+ // [Eugene to Paul] needs review!!
+ def typeArguments: List[rm.Type] = manifest[T].tpe.typeArguments
+ def typeVariables: List[java.lang.Class[_]] = typeArguments map (targ => rm.typeToClass(targ))
+ brackets(typeArguments map (jc => tvarString(List(jc))): _*)
+ }
/** Going for an overabundance of caution right now. Later these types
* can be a lot more precise, but right now the manifests have a habit of
diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala
index 4f6a4c8dc0..bbe22ca314 100644
--- a/src/compiler/scala/tools/nsc/matching/Patterns.scala
+++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala
@@ -187,9 +187,9 @@ trait Patterns extends ast.TreeDSL {
// As yet I can't testify this is doing any good relative to using
// tpt.tpe, but it doesn't seem to hurt either.
private lazy val packedType = global.typer.computeType(tpt, tpt.tpe)
- private lazy val consRef = appliedType(ConsClass.typeConstructor, List(packedType))
- private lazy val listRef = appliedType(ListClass.typeConstructor, List(packedType))
- private lazy val seqRef = appliedType(SeqClass.typeConstructor, List(packedType))
+ private lazy val consRef = appliedType(ConsClass, packedType)
+ private lazy val listRef = appliedType(ListClass, packedType)
+ private lazy val seqRef = appliedType(SeqClass, packedType)
private def thisSeqRef = {
val tc = (tree.tpe baseType SeqClass).typeConstructor
diff --git a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala
index 2ba8c8eb6b..ab8fe23909 100644
--- a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala
+++ b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala
@@ -35,17 +35,22 @@ abstract class AbstractReporter extends Reporter {
else _severity
if (severity == INFO) {
- if (isVerbose || force)
+ if (isVerbose || force) {
+ severity.count += 1
display(pos, msg, severity)
+ }
}
else {
val hidden = testAndLog(pos, severity)
if (severity == WARNING && noWarnings) ()
else {
- if (!hidden || isPromptSet)
+ if (!hidden || isPromptSet) {
+ severity.count += 1
display(pos, msg, severity)
- else if (settings.debug.value)
+ } else if (settings.debug.value) {
+ severity.count += 1
display(pos, "[ suppressed ] " + msg, severity)
+ }
if (isPromptSet)
displayPrompt
diff --git a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala
index f5335fb0f5..956c43c35a 100644
--- a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala
+++ b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala
@@ -75,7 +75,6 @@ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: Pr
}
def display(pos: Position, msg: String, severity: Severity) {
- severity.count += 1
if (severity != ERROR || severity.count <= ERROR_LIMIT)
print(pos, msg, severity)
}
diff --git a/src/compiler/scala/tools/nsc/scratchpad/Executor.scala b/src/compiler/scala/tools/nsc/scratchpad/Executor.scala
index ff0f94d897..8a918a829c 100644
--- a/src/compiler/scala/tools/nsc/scratchpad/Executor.scala
+++ b/src/compiler/scala/tools/nsc/scratchpad/Executor.scala
@@ -28,7 +28,7 @@ object Executor {
Console.setOut(newOut)
Console.setErr(newOut)
try {
- singletonInstance(name, classLoader)
+ singletonInstance(classLoader, name)
} catch {
case ex: Throwable =>
unwrapThrowable(ex) match {
diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
index e7959f36b2..ea12300785 100644
--- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
@@ -28,7 +28,7 @@ class MutableSettings(val errorFn: String => Unit)
settings
}
- protected def copyInto(settings: MutableSettings) {
+ def copyInto(settings: MutableSettings) {
allSettings foreach { thisSetting =>
val otherSetting = settings.allSettings find { _.name == thisSetting.name }
otherSetting foreach { otherSetting =>
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index c0b75fecc4..a89aa88585 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -81,6 +81,9 @@ trait ScalaSettings extends AbsScalaSettings
val XlogImplicits = BooleanSetting ("-Xlog-implicits", "Show more detail on why some implicits are not applicable.")
val logImplicitConv = BooleanSetting ("-Xlog-implicit-conversions", "Print a message whenever an implicit conversion is inserted.")
val logReflectiveCalls = BooleanSetting("-Xlog-reflective-calls", "Print a message when a reflective method call is generated")
+ val logRuntimeSplices = BooleanSetting("-Xlog-runtime-splices", "Print a message when Expr.eval or Expr.value cannot be resolved statically.")
+ val logFreeTerms = BooleanSetting ("-Xlog-free-terms", "Print a message when reification creates a free term.")
+ val logFreeTypes = BooleanSetting ("-Xlog-free-types", "Print a message when reification resorts to generating a free type.")
val maxClassfileName = IntSetting ("-Xmax-classfile-name", "Maximum filename length for generated classes", 255, Some((72, 255)), _ => None)
val Xmigration28 = BooleanSetting ("-Xmigration", "Warn about constructs whose behavior may have changed between 2.7 and 2.8.")
val nouescape = BooleanSetting ("-Xno-uescape", "Disable handling of \\u unicode escapes.")
@@ -117,62 +120,62 @@ trait ScalaSettings extends AbsScalaSettings
/**
* -Y "Private" settings
*/
- val overrideObjects = BooleanSetting ("-Yoverride-objects", "Allow member objects to be overridden.")
- val overrideVars = BooleanSetting ("-Yoverride-vars", "Allow vars to be overridden.")
- val Yhelp = BooleanSetting ("-Y", "Print a synopsis of private options.")
- val browse = PhasesSetting ("-Ybrowse", "Browse the abstract syntax tree after")
- val check = PhasesSetting ("-Ycheck", "Check the tree at the end of")
- val Yshow = PhasesSetting ("-Yshow", "(Requires -Xshow-class or -Xshow-object) Show after")
- val Xcloselim = BooleanSetting ("-Yclosure-elim", "Perform closure elimination.")
- val Ycompacttrees = BooleanSetting ("-Ycompact-trees", "Use compact tree printer when displaying trees.")
- val noCompletion = BooleanSetting ("-Yno-completion", "Disable tab-completion in the REPL.")
- val Xdce = BooleanSetting ("-Ydead-code", "Perform dead code elimination.")
- val debug = BooleanSetting ("-Ydebug", "Increase the quantity of debugging output.")
- // val doc = BooleanSetting ("-Ydoc", "Generate documentation")
- val termConflict = ChoiceSetting ("-Yresolve-term-conflict", "strategy", "Resolve term conflicts",
- List("package", "object", "error"), "error")
- val inline = BooleanSetting ("-Yinline", "Perform inlining when possible.")
- val inlineHandlers= BooleanSetting ("-Yinline-handlers", "Perform exception handler inlining when possible.")
- val Xlinearizer = ChoiceSetting ("-Ylinearizer", "which", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo")
- val log = PhasesSetting ("-Ylog", "Log operations during")
- val Ylogcp = BooleanSetting ("-Ylog-classpath", "Output information about what classpath is being applied.")
- val Ynogenericsig = BooleanSetting ("-Yno-generic-signatures", "Suppress generation of generic signatures for Java.")
- val noimports = BooleanSetting ("-Yno-imports", "Compile without importing scala.*, java.lang.*, or Predef.")
- val nopredef = BooleanSetting ("-Yno-predef", "Compile without importing Predef.")
- val noAdaptedArgs = BooleanSetting ("-Yno-adapted-args", "Do not adapt an argument list (either by inserting () or creating a tuple) to match the receiver.")
- val Yprofile = PhasesSetting ("-Yprofile", "(Requires jvm -agentpath to contain yjgpagent) Profile CPU usage of")
- val YprofileMem = BooleanSetting ("-Yprofile-memory", "Profile memory, get heap snapshot after each compiler run (requires yjpagent, see above).")
- val YprofileClass = StringSetting ("-Yprofile-class", "class", "Name of profiler class.", "scala.tools.util.YourkitProfiling")
- val Yrecursion = IntSetting ("-Yrecursion", "Set recursion depth used when locking symbols.", 0, Some((0, Int.MaxValue)), (_: String) => None)
- val selfInAnnots = BooleanSetting ("-Yself-in-annots", "Include a \"self\" identifier inside of annotations.")
- val Xshowtrees = BooleanSetting ("-Yshow-trees", "(Requires -Xprint:) Print detailed ASTs.")
- val Yshowsyms = BooleanSetting ("-Yshow-syms", "Print the AST symbol hierarchy after each phase.")
- val Yshowsymkinds = BooleanSetting ("-Yshow-symkinds", "Print abbreviated symbol kinds next to symbol names.")
- val skip = PhasesSetting ("-Yskip", "Skip")
- val Ygenjavap = StringSetting ("-Ygen-javap", "dir", "Generate a parallel output directory of .javap files.", "")
- val Ydumpclasses = StringSetting ("-Ydump-classes", "dir", "Dump the generated bytecode to .class files (useful for reflective compilation that utilizes in-memory classloaders).", "")
- val Ynosqueeze = BooleanSetting ("-Yno-squeeze", "Disable creation of compact code in matching.")
- val Ystatistics = BooleanSetting ("-Ystatistics", "Print compiler statistics.") andThen (util.Statistics.enabled = _)
- val stopAfter = PhasesSetting ("-Ystop-after", "Stop after") withAbbreviation ("-stop") // backward compat
- val stopBefore = PhasesSetting ("-Ystop-before", "Stop before")
- val refinementMethodDispatch =
- ChoiceSetting ("-Ystruct-dispatch", "policy", "structural method dispatch policy",
- List("no-cache", "mono-cache", "poly-cache", "invoke-dynamic"), "poly-cache")
- val globalClass = StringSetting ("-Yglobal-class", "class", "subclass of scala.tools.nsc.Global to use for compiler", "")
- val Yrangepos = BooleanSetting ("-Yrangepos", "Use range positions for syntax trees.")
- val YrichExes = BooleanSetting ("-Yrich-exceptions",
- "Fancier exceptions. Set source search path with -D" +
- sys.SystemProperties.traceSourcePath.key)
- val Ybuilderdebug = ChoiceSetting("-Ybuilder-debug", "manager", "Compile using the specified build manager.", List("none", "refined", "simple"), "none")
- val Yreifycopypaste =
- BooleanSetting ("-Yreify-copypaste", "Dump the reified trees in copypasteable representation.")
- val Yreplsync = BooleanSetting ("-Yrepl-sync", "Do not use asynchronous code for repl startup")
- val Ynotnull = BooleanSetting ("-Ynotnull", "Enable (experimental and incomplete) scala.NotNull.")
- val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overriden methods.")
- val etaExpandKeepsStar = BooleanSetting("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.")
- val noSelfCheck = BooleanSetting ("-Yno-self-type-checks", "Suppress check for self-type conformance among inherited members.")
- val YvirtPatmat = BooleanSetting ("-Yvirtpatmat", "Translate pattern matches into flatMap/orElse calls. See scala.MatchingStrategy.")
- val YvirtClasses = false // too embryonic to even expose as a -Y //BooleanSetting ("-Yvirtual-classes", "Support virtual classes")
+ val overrideObjects = BooleanSetting ("-Yoverride-objects", "Allow member objects to be overridden.")
+ val overrideVars = BooleanSetting ("-Yoverride-vars", "Allow vars to be overridden.")
+ val Yhelp = BooleanSetting ("-Y", "Print a synopsis of private options.")
+ val browse = PhasesSetting ("-Ybrowse", "Browse the abstract syntax tree after")
+ val check = PhasesSetting ("-Ycheck", "Check the tree at the end of")
+ val Yshow = PhasesSetting ("-Yshow", "(Requires -Xshow-class or -Xshow-object) Show after")
+ val Xcloselim = BooleanSetting ("-Yclosure-elim", "Perform closure elimination.")
+ val Ycompacttrees = BooleanSetting ("-Ycompact-trees", "Use compact tree printer when displaying trees.")
+ val noCompletion = BooleanSetting ("-Yno-completion", "Disable tab-completion in the REPL.")
+ val Xdce = BooleanSetting ("-Ydead-code", "Perform dead code elimination.")
+ val debug = BooleanSetting ("-Ydebug", "Increase the quantity of debugging output.")
+ //val doc = BooleanSetting ("-Ydoc", "Generate documentation")
+ val termConflict = ChoiceSetting ("-Yresolve-term-conflict", "strategy", "Resolve term conflicts", List("package", "object", "error"), "error")
+ val inline = BooleanSetting ("-Yinline", "Perform inlining when possible.")
+ val inlineHandlers = BooleanSetting ("-Yinline-handlers", "Perform exception handler inlining when possible.")
+ val Xlinearizer = ChoiceSetting ("-Ylinearizer", "which", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo")
+ val log = PhasesSetting ("-Ylog", "Log operations during")
+ val Ylogcp = BooleanSetting ("-Ylog-classpath", "Output information about what classpath is being applied.")
+ val Ynogenericsig = BooleanSetting ("-Yno-generic-signatures", "Suppress generation of generic signatures for Java.")
+ val noimports = BooleanSetting ("-Yno-imports", "Compile without importing scala.*, java.lang.*, or Predef.")
+ val nopredef = BooleanSetting ("-Yno-predef", "Compile without importing Predef.")
+ val noAdaptedArgs = BooleanSetting ("-Yno-adapted-args", "Do not adapt an argument list (either by inserting () or creating a tuple) to match the receiver.")
+ val Yprofile = PhasesSetting ("-Yprofile", "(Requires jvm -agentpath to contain yjgpagent) Profile CPU usage of")
+ val YprofileMem = BooleanSetting ("-Yprofile-memory", "Profile memory, get heap snapshot after each compiler run (requires yjpagent, see above).")
+ val YprofileClass = StringSetting ("-Yprofile-class", "class", "Name of profiler class.", "scala.tools.util.YourkitProfiling")
+ val Yrecursion = IntSetting ("-Yrecursion", "Set recursion depth used when locking symbols.", 0, Some((0, Int.MaxValue)), (_: String) => None)
+ val selfInAnnots = BooleanSetting ("-Yself-in-annots", "Include a \"self\" identifier inside of annotations.")
+ val Xshowtrees = BooleanSetting ("-Yshow-trees", "(Requires -Xprint:) Print detailed ASTs in formatted form.")
+ val XshowtreesCompact
+ = BooleanSetting ("-Yshow-trees-compact", "(Requires -Xprint:) Print detailed ASTs in compact form.")
+ val XshowtreesStringified
+ = BooleanSetting ("-Yshow-trees-stringified", "(Requires -Xprint:) Print stringifications along with detailed ASTs.")
+ val Yshowsyms = BooleanSetting ("-Yshow-syms", "Print the AST symbol hierarchy after each phase.")
+ val Yshowsymkinds = BooleanSetting ("-Yshow-symkinds", "Print abbreviated symbol kinds next to symbol names.")
+ val skip = PhasesSetting ("-Yskip", "Skip")
+ val Ygenjavap = StringSetting ("-Ygen-javap", "dir", "Generate a parallel output directory of .javap files.", "")
+ val Ydumpclasses = StringSetting ("-Ydump-classes", "dir", "Dump the generated bytecode to .class files (useful for reflective compilation that utilizes in-memory classloaders).", "")
+ val Ynosqueeze = BooleanSetting ("-Yno-squeeze", "Disable creation of compact code in matching.")
+ val Ystatistics = BooleanSetting ("-Ystatistics", "Print compiler statistics.") andThen (util.Statistics.enabled = _)
+ val stopAfter = PhasesSetting ("-Ystop-after", "Stop after") withAbbreviation ("-stop") // backward compat
+ val stopBefore = PhasesSetting ("-Ystop-before", "Stop before")
+ val refinementMethodDispatch
+ = ChoiceSetting ("-Ystruct-dispatch", "policy", "structural method dispatch policy", List("no-cache", "mono-cache", "poly-cache", "invoke-dynamic"), "poly-cache")
+ val globalClass = StringSetting ("-Yglobal-class", "class", "subclass of scala.tools.nsc.Global to use for compiler", "")
+ val Yrangepos = BooleanSetting ("-Yrangepos", "Use range positions for syntax trees.")
+ val YrichExes = BooleanSetting ("-Yrich-exceptions", "Fancier exceptions. Set source search path with -D" + sys.SystemProperties.traceSourcePath.key)
+ val Ybuilderdebug = ChoiceSetting ("-Ybuilder-debug", "manager", "Compile using the specified build manager.", List("none", "refined", "simple"), "none")
+ val Yreifycopypaste = BooleanSetting ("-Yreify-copypaste", "Dump the reified trees in copypasteable representation.")
+ val Ymacrocopypaste = BooleanSetting ("-Ymacro-copypaste", "Dump macro expansions in copypasteable representation.")
+ val Yreplsync = BooleanSetting ("-Yrepl-sync", "Do not use asynchronous code for repl startup")
+ val Ynotnull = BooleanSetting ("-Ynotnull", "Enable (experimental and incomplete) scala.NotNull.")
+ val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overriden methods.")
+ val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.")
+ val noSelfCheck = BooleanSetting ("-Yno-self-type-checks", "Suppress check for self-type conformance among inherited members.")
+ val YvirtPatmat = BooleanSetting ("-Yvirtpatmat", "Translate pattern matches into flatMap/orElse calls. See scala.MatchingStrategy.")
+ val YvirtClasses = false // too embryonic to even expose as a -Y //BooleanSetting ("-Yvirtual-classes", "Support virtual classes")
val exposeEmptyPackage = BooleanSetting("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly()
val YnoProductN = BooleanSetting ("-Yno-productN", "Do not add ProductN to case classes")
@@ -181,26 +184,30 @@ trait ScalaSettings extends AbsScalaSettings
/** Area-specific debug output.
*/
- val Ybuildmanagerdebug = BooleanSetting("-Ybuild-manager-debug", "Generate debug information for the Refined Build Manager compiler.")
- val Ycompletion = BooleanSetting("-Ycompletion-debug", "Trace all tab completion activity.")
- val Ydocdebug = BooleanSetting("-Ydoc-debug", "Trace all scaladoc activity.")
- val Yidedebug = BooleanSetting("-Yide-debug", "Generate, validate and output trees using the interactive compiler.")
- val Yinferdebug = BooleanSetting("-Yinfer-debug", "Trace type inference and implicit search.")
- val Ymacrodebug = BooleanSetting("-Ymacro-debug", "Trace macro-related activities: generation of synthetics, expansion, exceptions.")
- val Ypmatdebug = BooleanSetting("-Ypmat-debug", "Trace all pattern matcher activity.")
- val Yposdebug = BooleanSetting("-Ypos-debug", "Trace position validation.")
- val Yreifydebug = BooleanSetting("-Yreify-debug", "Trace reification.")
- val Yrepldebug = BooleanSetting("-Yrepl-debug", "Trace all repl activity.") andThen (interpreter.replProps.debug setValue _)
- val Ytyperdebug = BooleanSetting("-Ytyper-debug", "Trace all type assignments.")
+ val Ybuildmanagerdebug = BooleanSetting("-Ybuild-manager-debug", "Generate debug information for the Refined Build Manager compiler.")
+ val Ycompletion = BooleanSetting("-Ycompletion-debug", "Trace all tab completion activity.")
+ val Ydocdebug = BooleanSetting("-Ydoc-debug", "Trace all scaladoc activity.")
+ val Yidedebug = BooleanSetting("-Yide-debug", "Generate, validate and output trees using the interactive compiler.")
+ val Yinferdebug = BooleanSetting("-Yinfer-debug", "Trace type inference and implicit search.")
+ val Yissuedebug = BooleanSetting("-Yissue-debug", "Print stack traces when a context issues an error.")
+ val Ymacrodebug = BooleanSetting("-Ymacro-debug", "Trace macro-related activities: compilation, generation of synthetics, classloading, expansion, exceptions.")
+ val Ypmatdebug = BooleanSetting("-Ypmat-debug", "Trace all pattern matcher activity.")
+ val Yposdebug = BooleanSetting("-Ypos-debug", "Trace position validation.")
+ val Yreifydebug = BooleanSetting("-Yreify-debug", "Trace reification.")
+ val Yrepldebug = BooleanSetting("-Yrepl-debug", "Trace all repl activity.") andThen (interpreter.replProps.debug setValue _)
+ val Ytyperdebug = BooleanSetting("-Ytyper-debug", "Trace all type assignments.")
/** Groups of Settings.
*/
- val future = BooleanSetting ("-Xfuture", "Turn on future language features.") enabling futureSettings
- val optimise = BooleanSetting ("-optimise", "Generates faster bytecode by applying optimisations to the program") withAbbreviation "-optimize" enabling optimiseSettings
- val Xexperimental = BooleanSetting ("-Xexperimental", "Enable experimental extensions.") enabling experimentalSettings
+ val future = BooleanSetting("-Xfuture", "Turn on future language features.") enabling futureSettings
+ val optimise = BooleanSetting("-optimise", "Generates faster bytecode by applying optimisations to the program") withAbbreviation "-optimize" enabling optimiseSettings
+ val Xexperimental = BooleanSetting("-Xexperimental", "Enable experimental extensions.") enabling experimentalSettings
// Feature extensions
- val Xmacros = BooleanSetting ("-Xmacros", "Enable macros.")
+ val Xmacros = BooleanSetting("-Xmacros", "Enable macros.")
+ val XmacroSettings = MultiStringSetting("-Xmacro-settings", "option", "Custom settings for macros.")
+ val XmacroPrimaryClasspath = PathSetting("-Xmacro-primary-classpath", "Classpath to load macros implementations from, defaults to compilation classpath (aka \"library classpath\".", "")
+ val XmacroFallbackClasspath = PathSetting("-Xmacro-fallback-classpath", "Classpath to load macros implementations from if they cannot be loaded from library classpath.", "")
/**
* IDE-specific settings
diff --git a/src/compiler/scala/tools/nsc/symtab/Positions.scala b/src/compiler/scala/tools/nsc/symtab/Positions.scala
deleted file mode 100644
index 680b06f8ce..0000000000
--- a/src/compiler/scala/tools/nsc/symtab/Positions.scala
+++ /dev/null
@@ -1,30 +0,0 @@
-package scala.tools.nsc
-package symtab
-
-import scala.tools.nsc.util.{ SourceFile, Position, OffsetPosition, NoPosition }
-
-trait Positions extends scala.reflect.internal.Positions {
-self: scala.tools.nsc.symtab.SymbolTable =>
-
- def rangePos(source: SourceFile, start: Int, point: Int, end: Int) =
- new OffsetPosition(source, point)
-
- def validatePositions(tree: Tree) {}
-
- type Position = scala.tools.nsc.util.Position
- val NoPosition = scala.tools.nsc.util.NoPosition
-
- type TreeAnnotation = scala.tools.nsc.util.TreeAnnotation
- val NoTreeAnnotation: TreeAnnotation = NoPosition
- def positionToAnnotation(pos: Position): TreeAnnotation = pos
- def annotationToPosition(annot: TreeAnnotation): Position = annot.pos
- override def _checkSetAnnotation(tree: Tree, annot: TreeAnnotation): Unit = {
- if (tree.pos != NoPosition && tree.pos != annot.pos) debugwarn("Overwriting annotation "+ tree.annotation +" of tree "+ tree +" with annotation "+ annot)
- // if ((tree.annotation.isInstanceOf[scala.tools.nsc.util.Position] || !annot.isInstanceOf[scala.tools.nsc.util.Position]) && tree.isInstanceOf[Block])
- // println("Updating block from "+ tree.annotation +" to "+ annot)
- }
- def focusPos(pos: Position): Position = pos.focus
- def isRangePos(pos: Position): Boolean = pos.isRange
- def showPos(pos: Position): String = pos.show
-
-}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index 9dee441527..3d3cea75d6 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -776,7 +776,8 @@ abstract class ClassfileParser {
// with arrays of primitive types.
if (elemtp.typeSymbol.isAbstractType && !(elemtp <:< definitions.ObjectClass.tpe))
elemtp = intersectionType(List(elemtp, definitions.ObjectClass.tpe))
- appliedType(definitions.ArrayClass.tpe, List(elemtp))
+
+ definitions.arrayType(elemtp)
case '(' =>
// we need a method symbol. given in line 486 by calling getType(methodSym, ..)
assert(sym ne null, sig)
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
index 68af518d3a..775a7a9d38 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
@@ -625,11 +625,11 @@ abstract class ICodeReader extends ClassfileParser {
* such as Int.box(5).
*/
def isBox(m: Symbol): Boolean =
- (m.owner == definitions.BoxesRunTimeClass.moduleClass
+ (m.owner == definitions.BoxesRunTimeClass
&& m.name.startsWith("boxTo"))
def isUnbox(m: Symbol): Boolean =
- (m.owner == definitions.BoxesRunTimeClass.moduleClass
+ (m.owner == definitions.BoxesRunTimeClass
&& m.name.startsWith("unboxTo"))
/** Return the icode class that should include members with the given flags.
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
index 758f870d6b..edbe6df472 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
@@ -425,7 +425,7 @@ abstract class Pickler extends SubComponent {
private def putConstant(c: Constant) {
if (putEntry(c)) {
if (c.tag == StringTag) putEntry(newTermName(c.stringValue))
- else if (c.tag == ClassTag) putType(c.typeValue)
+ else if (c.tag == ClazzTag) putType(c.typeValue)
else if (c.tag == EnumTag) putSymbol(c.symbolValue)
}
}
@@ -606,7 +606,7 @@ abstract class Pickler extends SubComponent {
else if (c.tag == FloatTag) writeLong(floatToIntBits(c.floatValue))
else if (c.tag == DoubleTag) writeLong(doubleToLongBits(c.doubleValue))
else if (c.tag == StringTag) writeRef(newTermName(c.stringValue))
- else if (c.tag == ClassTag) writeRef(c.typeValue)
+ else if (c.tag == ClazzTag) writeRef(c.typeValue)
else if (c.tag == EnumTag) writeRef(c.symbolValue)
LITERAL + c.tag // also treats UnitTag, NullTag; no value required
case AnnotatedType(annotations, tp, selfsym) =>
@@ -1059,7 +1059,7 @@ abstract class Pickler extends SubComponent {
else if (c.tag == FloatTag) print("Float "+c.floatValue)
else if (c.tag == DoubleTag) print("Double "+c.doubleValue)
else if (c.tag == StringTag) { print("String "); printRef(newTermName(c.stringValue)) }
- else if (c.tag == ClassTag) { print("Class "); printRef(c.typeValue) }
+ else if (c.tag == ClazzTag) { print("Class "); printRef(c.typeValue) }
else if (c.tag == EnumTag) { print("Enum "); printRef(c.symbolValue) }
case AnnotatedType(annots, tp, selfsym) =>
if (settings.selfInAnnots.value) {
diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
index 39e2cbe694..5a11926048 100644
--- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
+++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
@@ -43,11 +43,7 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
*/
private def isInterfaceMember(sym: Symbol) = (
sym.isType || {
- // !!! Shouldn't the following code be equivalent to leaving
- // out the "sym.info" call and starting with "sym.initialize.isMethod" ?
- // Because, it is not, which I found a little disturbing. The compiler
- // fails to bootstrap with an error somewhere.
- sym.info // initialize to set lateMETHOD flag if necessary
+ sym.info // initialize to set lateMETHOD flag if necessary
( sym.isMethod
&& !sym.isLabel
@@ -68,57 +64,60 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
def implClassPhase = currentRun.erasurePhase.next
- /** Return the implementation class of a trait; create a new one of one does not yet exist */
- def implClass(iface: Symbol): Symbol = {
- iface.info
-
- implClassMap.getOrElse(iface, {
- atPhase(implClassPhase) {
- if (iface.implClass ne NoSymbol)
- log("%s.implClass == %s".format(iface, iface.implClass))
+ private def newImplClass(iface: Symbol): Symbol = {
+ val inClass = iface.owner.isClass
+ val implName = nme.implClassName(iface.name)
+ val implFlags = (iface.flags & ~(INTERFACE | lateINTERFACE)) | IMPLCLASS
- val implName = nme.implClassName(iface.name)
- var impl = if (iface.owner.isClass) iface.owner.info.decl(implName) else NoSymbol
-
- // !!! Why does forcing the impl's info here lead to a crash?
- // See test case pos/trait-force-info.scala for a minimization.
- // It crashes like this:
- //
- // [log lazyvals] trait ContextTrees.implClass == class ContextTrees$class
- // error: java.lang.AssertionError: assertion failed: (scala.tools.nsc.typechecker.Contexts$NoContext$,scala.tools.nsc.typechecker.Contexts,NoContext$,trait Contexts in package typechecker) / while parsing (/scala/trunk/build/pack/lib/scala-compiler.jar(scala/tools/nsc/interactive/ContextTrees$class.class),Some(class ContextTrees$class))trait Contexts.NoContext$ linkedModule: <none>List()
-
- val originalImpl = impl
- if (impl != NoSymbol) {
+ val impl0 = (
+ if (!inClass) NoSymbol
+ else iface.owner.info.decl(implName) match {
+ case NoSymbol => NoSymbol
+ case implSym =>
// Unlink a pre-existing symbol only if the implementation class is
// visible on the compilation classpath. In general this is true under
// -optimise and not otherwise, but the classpath can use arbitrary
// logic so the classpath must be queried.
if (classPath.context.isValidName(implName + ".class")) {
- log("unlinking impl class " + impl)
- iface.owner.info.decls.unlink(impl)
- impl = NoSymbol
+ log("unlinking impl class " + implSym)
+ iface.owner.info.decls unlink implSym
+ NoSymbol
+ }
+ else {
+ log("not unlinking existing " + implSym + " as the impl class is not visible on the classpath.")
+ implSym
}
- else log("not unlinking existing " + impl + " as the impl class is not visible on the classpath.")
- }
- if (impl == NoSymbol) {
- impl = iface.cloneSymbolImpl(iface.owner)
- impl.name = implName
- impl.sourceFile = iface.sourceFile
- if (iface.owner.isClass)
- iface.owner.info.decls enter impl
- }
- if (currentRun.compiles(iface)) currentRun.symSource(impl) = iface.sourceFile
- impl setPos iface.pos
- impl.flags = iface.flags & ~(INTERFACE | lateINTERFACE) | IMPLCLASS
- impl setInfo new LazyImplClassType(iface)
- implClassMap(iface) = impl
- debuglog(
- "generating impl class " + impl.debugLocationString + " in " + iface.owner + (
- if (originalImpl == NoSymbol) "" else " (cloned from " + originalImpl.debugLocationString + ")"
- )
- )
- impl
}
+ )
+ val impl = impl0 orElse {
+ val impl = iface.owner.newImplClass(implName, iface.pos, implFlags)
+ if (iface.thisSym != iface) {
+ impl.typeOfThis = iface.typeOfThis
+ impl.thisSym setName iface.thisSym.name
+ }
+ impl.sourceFile = iface.sourceFile
+ if (inClass)
+ iface.owner.info.decls enter impl
+
+ impl
+ }
+ if (currentRun compiles iface)
+ currentRun.symSource(impl) = iface.sourceFile
+
+ implClassMap(iface) = impl
+ impl setInfo new LazyImplClassType(iface)
+ }
+
+ /** Return the implementation class of a trait; create a new one of one does not yet exist */
+ def implClass(iface: Symbol): Symbol = {
+ iface.info
+
+ implClassMap.getOrElse(iface, atPhase(implClassPhase) {
+ log("Creating implClass for " + iface)
+ if (iface.implClass ne NoSymbol)
+ log("%s.implClass already exists: %s".format(iface, iface.implClass))
+
+ newImplClass(iface)
})
}
@@ -138,22 +137,31 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
* given the decls ifaceDecls of its interface.
*/
private def implDecls(implClass: Symbol, ifaceDecls: Scope): Scope = {
+ log("LazyImplClassType calculating decls for " + implClass)
+
val decls = newScope
- if ((ifaceDecls lookup nme.MIXIN_CONSTRUCTOR) == NoSymbol)
+ if ((ifaceDecls lookup nme.MIXIN_CONSTRUCTOR) == NoSymbol) {
+ log("Adding mixin constructor to " + implClass)
+
decls enter (
implClass.newMethod(nme.MIXIN_CONSTRUCTOR, implClass.pos)
setInfo MethodType(Nil, UnitClass.tpe)
)
+ }
- for (sym <- ifaceDecls.iterator) {
+ for (sym <- ifaceDecls) {
if (isInterfaceMember(sym)) {
if (needsImplMethod(sym)) {
- val impl = sym.cloneSymbol(implClass).resetFlag(lateDEFERRED)
- if (currentRun.compiles(implClass)) implMethodMap(sym) = impl
- decls enter impl
+ log("Cloning " + sym + " for implementation method in " + implClass)
+ val clone = sym.cloneSymbol(implClass).resetFlag(lateDEFERRED)
+ if (currentRun.compiles(implClass)) implMethodMap(sym) = clone
+ decls enter clone
sym setFlag lateDEFERRED
}
- } else {
+ else log(sym + " needs no implementation method in " + implClass)
+ }
+ else {
+ log("Destructively modifying owner of %s from %s to %s".format(sym, sym.owner, implClass))
sym.owner = implClass
// note: OK to destructively modify the owner here,
// because symbol will not be accessible from outside the sourcefile.
@@ -161,14 +169,17 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
decls enter sym
}
}
+
decls
}
- override def complete(sym: Symbol) {
+ override def complete(implSym: Symbol) {
+ log("LazyImplClassType completing " + implSym)
+
/** If `tp` refers to a non-interface trait, return a
* reference to its implementation class. Otherwise return `tp`.
*/
- def mixinToImplClass(tp: Type): Type = erasure(sym) {
+ def mixinToImplClass(tp: Type): Type = AddInterfaces.this.erasure(implSym) {
tp match { //@MATN: no normalize needed (comes after erasure)
case TypeRef(pre, sym, _) if sym.needsImplClass =>
typeRef(pre, implClass(sym), Nil)
@@ -179,15 +190,13 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
def implType(tp: Type): Type = tp match {
case ClassInfoType(parents, decls, _) =>
assert(phase == implClassPhase, tp)
- ClassInfoType(
- ObjectClass.tpe +: (parents.tail map mixinToImplClass filter (_.typeSymbol != ObjectClass)) :+ iface.tpe,
- implDecls(sym, decls),
- sym
- )
+ // Impl class parents: Object first, matching interface last.
+ val implParents = ObjectClass.tpe +: (parents.tail map mixinToImplClass filter (_.typeSymbol != ObjectClass)) :+ iface.tpe
+ ClassInfoType(implParents, implDecls(implSym, decls), implSym)
case PolyType(_, restpe) =>
implType(restpe)
}
- sym setInfo implType(beforeErasure(iface.info))
+ implSym setInfo implType(beforeErasure(iface.info))
}
override def load(clazz: Symbol) { complete(clazz) }
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index b21fa4bc83..eea87c8ba6 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -299,11 +299,11 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
def testForName(name: Name): Tree => Tree = t => (
if (nme.CommonOpNames(name))
- gen.mkMethodCall(getMember(BoxesRunTimeClass, nme.isBoxedNumberOrBoolean), t :: Nil)
+ gen.mkMethodCall(definitions.Boxes_isNumberOrBool, t :: Nil)
else if (nme.BooleanOpNames(name))
t IS_OBJ BoxedBooleanClass.tpe
else
- gen.mkMethodCall(getMember(BoxesRunTimeClass, nme.isBoxedNumber), t :: Nil)
+ gen.mkMethodCall(definitions.Boxes_isNumber, t :: Nil)
)
/** The Tree => Tree function in the return is necessary to prevent the original qual
@@ -318,8 +318,10 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
else if (params.tail.isEmpty) nme.primitiveInfixMethodName(name)
else nme.NO_NAME
)
- if (methodName == nme.NO_NAME) None
- else Some((getMember(BoxesRunTimeClass, methodName), testForName(name)))
+ definitions.getDeclIfDefined(BoxesRunTimeClass, methodName) match {
+ case NoSymbol => None
+ case sym => assert(!sym.isOverloaded, sym) ; Some((sym, testForName(name)))
+ }
}
/* ### BOXING PARAMS & UNBOXING RESULTS ### */
@@ -540,7 +542,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
if (forMSIL) savingStatics( transformTemplate(tree) )
else transformTemplate(tree)
- case Literal(c) if (c.tag == ClassTag) && !forMSIL=>
+ case Literal(c) if (c.tag == ClazzTag) && !forMSIL=>
val tpe = c.typeValue
typedWithPos(tree.pos) {
if (isPrimitiveValueClass(tpe.typeSymbol)) {
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 0c867b9e7e..e2ce3b62b4 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -734,7 +734,7 @@ abstract class Erasure extends AddInterfaces
/** A replacement for the standard typer's `typed1` method.
*/
- override protected def typed1(tree: Tree, mode: Int, pt: Type): Tree = {
+ override def typed1(tree: Tree, mode: Int, pt: Type): Tree = {
val tree1 = try {
tree match {
case InjectDerivedValue(arg) =>
@@ -1090,7 +1090,7 @@ abstract class Erasure extends AddInterfaces
case Match(selector, cases) =>
Match(Typed(selector, TypeTree(selector.tpe)), cases)
- case Literal(ct) if ct.tag == ClassTag
+ case Literal(ct) if ct.tag == ClazzTag
&& ct.typeValue.typeSymbol != definitions.UnitClass =>
val erased = ct.typeValue match {
case TypeRef(pre, clazz, args) if clazz.isDerivedValueClass => scalaErasure.eraseNormalClassRef(pre, clazz)
@@ -1134,10 +1134,10 @@ abstract class Erasure extends AddInterfaces
*/
override def transform(tree: Tree): Tree = {
val tree1 = preTransformer.transform(tree)
- log("tree after pretransform: "+tree1)
+ // log("tree after pretransform: "+tree1)
afterErasure {
val tree2 = mixinTransformer.transform(tree1)
- debuglog("tree after addinterfaces: \n" + tree2)
+ // debuglog("tree after addinterfaces: \n" + tree2)
newTyper(rootContext(unit, tree, true)).typed(tree2)
}
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index 595c1486b6..16c7c3c3ff 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -93,7 +93,7 @@ abstract class ExplicitOuter extends InfoTransform
}
def newOuterAccessor(clazz: Symbol) = {
val accFlags = SYNTHETIC | METHOD | STABLE | ( if (clazz.isTrait) DEFERRED else 0 )
- val sym = clazz.newMethodSymbol(nme.OUTER, clazz.pos, accFlags)
+ val sym = clazz.newMethod(nme.OUTER, clazz.pos, accFlags)
val restpe = if (clazz.isTrait) clazz.outerClass.tpe else clazz.outerClass.thisType
sym expandName clazz
diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
index 5104518dd9..3515c1d521 100644
--- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
@@ -68,7 +68,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
private def normalize(stpe: Type, clazz: Symbol): Type = stpe match {
case PolyType(tparams, restpe) =>
- GenPolyType(tparams dropRight clazz.typeParams.length, normalize(restpe, clazz))
+ GenPolyType(tparams dropRight clazz.typeParams.length, normalize(restpe.substSym(tparams takeRight clazz.typeParams.length, clazz.typeParams), clazz))
case MethodType(tparams, restpe) =>
restpe
case _ =>
diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala
index 8856024a30..c8de25b2ea 100644
--- a/src/compiler/scala/tools/nsc/transform/Flatten.scala
+++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala
@@ -27,6 +27,7 @@ abstract class Flatten extends InfoTransform {
scope unlink old
scope enter sym
+ log("lifted " + sym.fullLocationString)
old
}
@@ -36,7 +37,7 @@ abstract class Flatten extends InfoTransform {
debuglog("re-enter " + sym.fullLocationString)
val old = replaceSymbolInCurrentScope(sym)
if (old ne NoSymbol)
- debuglog("lifted " + sym.fullLocationString + ", unlinked " + old)
+ log("unlinked " + old.fullLocationString + " after lifting " + sym)
}
}
private def liftSymbol(sym: Symbol) {
@@ -108,7 +109,7 @@ abstract class Flatten extends InfoTransform {
tree match {
case PackageDef(_, _) =>
liftedDefs(tree.symbol.moduleClass) = new ListBuffer
- case Template(_, _, _) if tree.symbol.owner.hasPackageFlag =>
+ case Template(_, _, _) if tree.symbol.isDefinedInPackage =>
liftedDefs(tree.symbol.owner) = new ListBuffer
case _ =>
}
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index 13ca8e55bc..6bddfe8d57 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -19,19 +19,6 @@ abstract class LambdaLift extends InfoTransform {
/** the following two members override abstract members in Transform */
val phaseName: String = "lambdalift"
- /** Converts types of captured variables to *Ref types.
- */
- def boxIfCaptured(sym: Symbol, tpe: Type, erasedTypes: Boolean) =
- if (sym.isCapturedVariable) {
- val symClass = tpe.typeSymbol
- def refType(valueRef: Map[Symbol, Symbol], objectRefClass: Symbol) =
- if (isPrimitiveValueClass(symClass) && symClass != UnitClass) valueRef(symClass).tpe
- else if (erasedTypes) objectRefClass.tpe
- else appliedType(objectRefClass.typeConstructor, List(tpe))
- if (sym.hasAnnotation(VolatileAttr)) refType(volatileRefClass, VolatileObjectRefClass)
- else refType(refClass, ObjectRefClass)
- } else tpe
-
private val lifted = new TypeMap {
def apply(tp: Type): Type = tp match {
case TypeRef(NoPrefix, sym, Nil) if sym.isClass && !sym.isPackageClass =>
@@ -46,7 +33,8 @@ abstract class LambdaLift extends InfoTransform {
}
def transformInfo(sym: Symbol, tp: Type): Type =
- boxIfCaptured(sym, lifted(tp), erasedTypes = true)
+ if (sym.isCapturedVariable) capturedVariableType(sym, tpe = lifted(tp), erasedTypes = true)
+ else lifted(tp)
protected def newTransformer(unit: CompilationUnit): Transformer =
new LambdaLifter(unit)
@@ -229,10 +217,10 @@ abstract class LambdaLift extends InfoTransform {
sym.owner.name + nme.NAME_JOIN_STRING
else ""
)
- sym.name =
+ sym setName (
if (sym.name.isTypeName) unit.freshTypeName(base)
else unit.freshTermName(base)
-
+ )
debuglog("renaming in %s: %s => %s".format(sym.owner.fullLocationString, originalName, sym.name))
}
@@ -241,7 +229,7 @@ abstract class LambdaLift extends InfoTransform {
def renameTrait(traitSym: Symbol, implSym: Symbol) {
val originalImplName = implSym.name
renameSym(traitSym)
- implSym.name = nme.implClassName(traitSym.name)
+ implSym setName nme.implClassName(traitSym.name)
debuglog("renaming impl class in step with %s: %s => %s".format(traitSym, originalImplName, implSym.name))
}
@@ -471,6 +459,8 @@ abstract class LambdaLift extends InfoTransform {
private def preTransform(tree: Tree) = super.transform(tree) setType lifted(tree.tpe)
override def transform(tree: Tree): Tree = tree match {
+ case Select(ReferenceToBoxed(idt), elem) if elem == nme.elem =>
+ postTransform(preTransform(idt), isBoxedRef = false)
case ReferenceToBoxed(idt) =>
postTransform(preTransform(idt), isBoxedRef = true)
case _ =>
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index adbb7d43d0..0e4975c04c 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -136,7 +136,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
sym = member.matchingSymbol(bcs.head, base.thisType).suchThat(sym => !sym.hasFlag(DEFERRED | BRIDGE))
bcs = bcs.tail
}
- assert(sym != NoSymbol, member)
sym
}
@@ -339,8 +338,14 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
else if (mixinMember.isSuperAccessor) { // mixin super accessors
val superAccessor = addMember(clazz, mixinMember.cloneSymbol(clazz)) setPos clazz.pos
assert(superAccessor.alias != NoSymbol, superAccessor)
- val alias1 = rebindSuper(clazz, mixinMember.alias, mixinClass)
- superAccessor.asInstanceOf[TermSymbol] setAlias alias1
+
+ rebindSuper(clazz, mixinMember.alias, mixinClass) match {
+ case NoSymbol =>
+ unit.error(clazz.pos, "Member %s of mixin %s is missing a concrete super implementation.".format(
+ mixinMember.alias, mixinClass))
+ case alias1 =>
+ superAccessor.asInstanceOf[TermSymbol] setAlias alias1
+ }
}
else if (mixinMember.isMethod && mixinMember.isModule && mixinMember.hasNoFlags(LIFTED | BRIDGE)) {
// mixin objects: todo what happens with abstract objects?
@@ -384,11 +389,14 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
var sourceModule = clazz.owner.info.decls.lookup(sym.name.toTermName)
if (sourceModule != NoSymbol) {
sourceModule setPos sym.pos
- sourceModule.flags = MODULE | FINAL
+ if (sourceModule.flags != MODULE) {
+ log("!!! Directly setting sourceModule flags from %s to MODULE".format(flagsToString(sourceModule.flags)))
+ sourceModule.flags = MODULE
+ }
}
else {
sourceModule = (
- clazz.owner.newModuleSymbol(sym.name.toTermName, sym.pos, MODULE | FINAL)
+ clazz.owner.newModuleSymbol(sym.name.toTermName, sym.pos, MODULE)
setModuleClass sym.asInstanceOf[ClassSymbol]
)
clazz.owner.info.decls enter sourceModule
@@ -930,7 +938,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
private def checkedGetter(lhs: Tree) = {
val sym = clazz.info decl lhs.symbol.getterName suchThat (_.isGetter)
if (needsInitAndHasOffset(sym)) {
- debuglog("adding checked getter for: " + sym + " " + lhs.symbol.defaultFlagString)
+ debuglog("adding checked getter for: " + sym + " " + lhs.symbol.flagString)
List(localTyper typed mkSetFlag(clazz, fieldOffset(sym), sym))
}
else Nil
@@ -1077,7 +1085,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
// add forwarders
assert(sym.alias != NoSymbol, sym)
// debuglog("New forwarder: " + sym.defString + " => " + sym.alias.defString)
- addDefDef(sym, Apply(staticRef(sym.alias), gen.mkAttributedThis(clazz) :: sym.paramss.head.map(Ident)))
+ if (!sym.isTermMacro) addDefDef(sym, Apply(staticRef(sym.alias), gen.mkAttributedThis(clazz) :: sym.paramss.head.map(Ident)))
}
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 1afa1dbf58..12d2513756 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -67,8 +67,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
import definitions.{
RootClass, BooleanClass, UnitClass, ArrayClass,
ScalaValueClasses, isPrimitiveValueClass, isScalaValueType,
- SpecializedClass, RepeatedParamClass, JavaRepeatedParamClass,
- AnyRefClass, ObjectClass, AnyRefModule,
+ SpecializedClass, AnyRefClass, ObjectClass, AnyRefModule,
GroupOfSpecializable, uncheckedVarianceClass, ScalaInlineClass
}
@@ -99,9 +98,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
/** Concrete methods that use a specialized type, or override such methods. */
private val concreteSpecMethods = perRunCaches.newWeakSet[Symbol]()
- private def isSpecialized(sym: Symbol) = sym hasAnnotation SpecializedClass
- private def hasSpecializedFlag(sym: Symbol) = sym hasFlag SPECIALIZED
- private def specializedTypes(tps: List[Symbol]) = tps filter isSpecialized
+ private def specializedTypes(tps: List[Symbol]) = tps filter (_.isSpecialized)
private def specializedOn(sym: Symbol): List[Symbol] = {
sym getAnnotation SpecializedClass match {
case Some(AnnotationInfo(_, Nil, _)) => specializableTypes.map(_.typeSymbol)
@@ -128,11 +125,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
isBoundedGeneric(tp)
//(tp <:< AnyRefClass.tpe)
}
- private def isBoundedGeneric(tp: Type) = tp match {
- case TypeRef(_, sym, _) if sym.isAbstractType => (tp <:< AnyRefClass.tpe)
- case TypeRef(_, sym, _) => !isPrimitiveValueClass(sym)
- case _ => false
- }
object TypeEnv {
/** Return a new type environment binding specialized type parameters of sym to
@@ -141,7 +133,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
def fromSpecialization(sym: Symbol, args: List[Type]): TypeEnv = {
ifDebug(assert(sym.info.typeParams.length == args.length, sym + " args: " + args))
- emptyEnv ++ collectMap2(sym.info.typeParams, args)((k, v) => isSpecialized(k))
+ emptyEnv ++ collectMap2(sym.info.typeParams, args)((k, v) => k.isSpecialized)
}
/** Does typeenv `t1` include `t2`? All type variables in `t1`
@@ -166,7 +158,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
*/
def isValid(env: TypeEnv, sym: Symbol): Boolean = {
env forall { case (tvar, tpe) =>
- isSpecialized(tvar) && (concreteTypes(tvar) contains tpe) && {
+ tvar.isSpecialized && (concreteTypes(tvar) contains tpe) && {
(sym.typeParams contains tvar) ||
(sym.owner != RootClass && (sym.owner.typeParams contains tvar))
}
@@ -178,7 +170,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
* 'sClass' itself if sClass is not a specialized subclass.
*/
def genericClass(sClass: Symbol): Symbol =
- if (hasSpecializedFlag(sClass)) sClass.superClass
+ if (sClass.isSpecialized) sClass.superClass
else sClass
case class Overload(sym: Symbol, env: TypeEnv) {
@@ -243,7 +235,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
/** Type bounds of a @specialized type var are now in the environment. */
override def typeBoundsIn(env: TypeEnv): Boolean = {
target.info.typeParams exists { tvar =>
- isSpecialized(tvar) && (specializedTypeVars(tvar.info.bounds) exists env.isDefinedAt)
+ tvar.isSpecialized && (specializedTypeVars(tvar.info.bounds) exists env.isDefinedAt)
}
}
@@ -259,21 +251,21 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
/** Has `clazz` any type parameters that need be specialized? */
def hasSpecializedParams(clazz: Symbol) =
- clazz.info.typeParams exists isSpecialized
+ clazz.info.typeParams exists (_.isSpecialized)
/** Return specialized type parameters. */
def specializedParams(sym: Symbol): List[Symbol] =
- sym.info.typeParams filter isSpecialized
+ sym.info.typeParams filter (_.isSpecialized)
def splitParams(tps: List[Symbol]) =
- tps partition isSpecialized
+ tps partition (_.isSpecialized)
/** Given an original class symbol and a list of types its type parameters are instantiated at
* returns a list of type parameters that should remain in the TypeRef when instantiating a
* specialized type.
*/
def survivingArgs(sym: Symbol, args: List[Type]): List[Type] =
- for ((tvar, tpe) <- sym.info.typeParams.zip(args) if !isSpecialized(tvar) || !isScalaValueType(tpe))
+ for ((tvar, tpe) <- sym.info.typeParams.zip(args) if !tvar.isSpecialized || !isScalaValueType(tpe))
yield tpe
val specializedType = new TypeMap {
@@ -347,7 +339,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
* These are in a meaningful order for stability purposes.
*/
def concreteTypes(sym: Symbol): List[Type] = {
- val types = if (!isSpecialized(sym))
+ val types = if (!sym.isSpecialized)
Nil // no @specialized Annotation
else
specializedOn(sym) map (s => specializesClass(s).tpe) sorted
@@ -363,7 +355,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
*/
private def specializations(tps: List[Symbol]): List[TypeEnv] = {
// the keys in each TypeEnv
- val keys: List[Symbol] = tps filter isSpecialized
+ val keys: List[Symbol] = tps filter (_.isSpecialized)
// creating each permutation of concrete types
def loop(ctypes: List[List[Type]]): List[List[Type]] = ctypes match {
case Nil => Nil
@@ -384,11 +376,11 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
*/
private def needsSpecialization(env: TypeEnv, sym: Symbol): Boolean = {
specializedTypeVars(sym).intersect(env.keySet).diff(wasSpecializedForTypeVars(sym)).nonEmpty ||
- (sym.isClassConstructor && (sym.enclClass.typeParams exists isSpecialized)) ||
+ (sym.isClassConstructor && (sym.enclClass.typeParams exists (_.isSpecialized))) ||
(isNormalizedMember(sym) && info(sym).typeBoundsIn(env))
}
- def isNormalizedMember(m: Symbol) = hasSpecializedFlag(m) && (info get m exists {
+ def isNormalizedMember(m: Symbol) = m.isSpecialized && (info get m exists {
case NormalizedMember(_) => true
case _ => false
})
@@ -409,14 +401,14 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
case TypeRef(pre, sym, args) =>
if (sym.isAliasType)
specializedTypeVars(tpe.normalize)
- else if (sym.isTypeParameter && isSpecialized(sym) || (sym.isTypeSkolem && isSpecialized(sym.deSkolemize)))
+ else if (sym.isTypeParameter && sym.isSpecialized || (sym.isTypeSkolem && sym.deSkolemize.isSpecialized))
Set(sym)
else if (sym == ArrayClass)
specializedTypeVars(args)
else if (args.isEmpty)
Set()
else
- specializedTypeVars(sym.typeParams zip args collect { case (tp, arg) if isSpecialized(tp) => arg })
+ specializedTypeVars(sym.typeParams zip args collect { case (tp, arg) if tp.isSpecialized => arg })
case PolyType(tparams, resTpe) => specializedTypeVars(resTpe :: tparams.map(_.info))
// since this method may be run at phase typer (before uncurry, where NMTs are eliminated)
@@ -450,7 +442,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
/** Type parameters that survive when specializing in the specified environment. */
def survivingParams(params: List[Symbol], env: TypeEnv) =
- params.filter(p => !isSpecialized(p) || !isScalaValueType(env(p)))
+ params.filter(p => !p.isSpecialized || !isScalaValueType(env(p)))
/** Produces the symbols from type parameters `syms` of the original owner,
* in the given type environment `env`. The new owner is `nowner`.
@@ -513,8 +505,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
val sClass = clazz.owner.newClass(clazzName, clazz.pos, (clazz.flags | SPECIALIZED) & ~CASE)
- def cloneInSpecializedClass(member: Symbol, flagFn: Long => Long) =
- member.cloneSymbol(sClass, flagFn(member.flags | SPECIALIZED))
+ def cloneInSpecializedClass(member: Symbol, flagFn: Long => Long, newName: Name = null) =
+ member.cloneSymbol(sClass, flagFn(member.flags | SPECIALIZED), newName)
sClass.sourceFile = clazz.sourceFile
currentRun.symSource(sClass) = clazz.sourceFile // needed later on by mixin
@@ -726,7 +718,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
else if (m.isClass) {
val specClass: Symbol = cloneInSpecializedClass(m, x => x)
typeEnv(specClass) = fullEnv
- specClass.name = specializedName(specClass, fullEnv).toTypeName
+ specClass setName specializedName(specClass, fullEnv).toTypeName
enterMember(specClass)
debuglog("entered specialized class " + specClass.fullName)
info(specClass) = SpecializedInnerClass(m, fullEnv)
@@ -804,7 +796,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
val env = mapAnyRefsInSpecSym(env0, sym, specMember)
val (keys, vals) = env.toList.unzip
- specMember.name = specializedName(sym, env)
+ specMember setName specializedName(sym, env)
// debuglog("%s normalizes to %s%s".format(sym, specMember,
// if (tps.isEmpty) "" else " with params " + tps.mkString(", ")))
@@ -882,10 +874,11 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
/** Return the specialized overload of `m`, in the given environment. */
private def specializedOverload(owner: Symbol, sym: Symbol, env: TypeEnv): Symbol = {
+ val newFlags = (sym.flags | SPECIALIZED) & ~(DEFERRED | CASEACCESSOR | ACCESSOR | LAZY)
// this method properly duplicates the symbol's info
- val specMember = sym.cloneSymbol(owner, (sym.flags | SPECIALIZED) & ~(DEFERRED | CASEACCESSOR | ACCESSOR | LAZY))
- specMember.name = specializedName(sym, env)
- specMember modifyInfo (info => subst(env, info.asSeenFrom(owner.thisType, sym.owner)))
+ ( sym.cloneSymbol(owner, newFlags, specializedName(sym, env))
+ modifyInfo (info => subst(env, info.asSeenFrom(owner.thisType, sym.owner)))
+ )
}
/** For each method m that overrides an inherited method m', add a special
@@ -993,7 +986,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
* If `strict` is true, a UnifyError is thrown if unification is impossible.
*/
private def unify(tp1: Type, tp2: Type, env: TypeEnv, strict: Boolean): TypeEnv = (tp1, tp2) match {
- case (TypeRef(_, sym1, _), _) if isSpecialized(sym1) =>
+ case (TypeRef(_, sym1, _), _) if sym1.isSpecialized =>
debuglog("Unify " + tp1 + ", " + tp2)
if (isPrimitiveValueClass(tp2.typeSymbol) || isSpecializedAnyRefSubtype(tp2, sym1))
env + ((sym1, tp2))
@@ -1234,13 +1227,13 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
/** Return the generic class corresponding to this specialized class. */
def originalClass(clazz: Symbol): Symbol =
- if (hasSpecializedFlag(clazz)) {
+ if (clazz.isSpecialized) {
val (originalName, _, _) = nme.splitSpecializedName(clazz.name)
clazz.owner.info.decl(originalName).suchThat(_.isClass)
} else NoSymbol
def illegalSpecializedInheritance(clazz: Symbol): Boolean = (
- hasSpecializedFlag(clazz)
+ clazz.isSpecialized
&& originalClass(clazz).parentSymbols.exists(p => hasSpecializedParams(p) && !p.isTrait)
)
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 0efdd9ab9f..11f06a0541 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -126,7 +126,7 @@ abstract class UnCurry extends InfoTransform
/** The type of a non-local return expression with given argument type */
private def nonLocalReturnExceptionType(argtype: Type) =
- appliedType(NonLocalReturnControlClass.typeConstructor, List(argtype))
+ appliedType(NonLocalReturnControlClass, argtype)
/** A hashmap from method symbols to non-local return keys */
private val nonLocalReturnKeys = perRunCaches.newMap[Symbol, Symbol]()
@@ -244,7 +244,7 @@ abstract class UnCurry extends InfoTransform
def parents =
if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe)
- else if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe)
+ else if (isPartial) List(appliedType(AbstractPartialFunctionClass, targs: _*), SerializableClass.tpe)
else List(ObjectClass.tpe, fun.tpe, SerializableClass.tpe)
val anonClass = owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation serialVersionUIDAnnotation
@@ -358,18 +358,18 @@ abstract class UnCurry extends InfoTransform
def sequenceToArray(tree: Tree) = {
val toArraySym = tree.tpe member nme.toArray
assert(toArraySym != NoSymbol)
- def getManifest(tp: Type): Tree = {
- val manifestOpt = localTyper.findManifest(tp, false)
+ def getClassTag(tp: Type): Tree = {
+ val tag = localTyper.resolveClassTag(tree, tp)
// Don't want bottom types getting any further than this (SI-4024)
- if (tp.typeSymbol.isBottomClass) getManifest(AnyClass.tpe)
- else if (!manifestOpt.tree.isEmpty) manifestOpt.tree
- else if (tp.bounds.hi ne tp) getManifest(tp.bounds.hi)
- else localTyper.getManifestTree(tree, tp, false)
+ if (tp.typeSymbol.isBottomClass) getClassTag(AnyClass.tpe)
+ else if (!tag.isEmpty) tag
+ else if (tp.bounds.hi ne tp) getClassTag(tp.bounds.hi)
+ else localTyper.TyperErrorGen.MissingClassTagError(tree, tp)
}
afterUncurry {
localTyper.typedPos(pos) {
Apply(gen.mkAttributedSelect(tree, toArraySym),
- List(getManifest(tree.tpe.baseType(TraversableClass).typeArgs.head)))
+ List(getClassTag(tree.tpe.baseType(TraversableClass).typeArgs.head)))
}
}
}
@@ -494,6 +494,12 @@ abstract class UnCurry extends InfoTransform
}
val sym = tree.symbol
+ // Take a pass looking for @specialize annotations and set all
+ // their SPECIALIZE flags for cheaper recognition.
+ if ((sym ne null) && (sym.isClass || sym.isMethod)) {
+ for (tp <- sym.typeParams ; if tp hasAnnotation SpecializedClass)
+ tp setFlag SPECIALIZED
+ }
val result = (
// TODO - settings.noassertions.value temporarily retained to avoid
// breakage until a reasonable interface is settled upon.
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 49ddb985dc..edc69be827 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -277,11 +277,6 @@ trait ContextErrors {
setError(tree)
}
- def MultiDimensionalArrayError(tree: Tree) = {
- issueNormalTypeError(tree, "cannot create a generic multi-dimensional array of more than "+ definitions.MaxArrayDims+" dimensions")
- setError(tree)
- }
-
//typedSuper
def MixinMissingParentClassNameError(tree: Tree, mix: Name, clazz: Symbol) =
issueNormalTypeError(tree, mix+" does not name a parent class of "+clazz)
@@ -344,6 +339,11 @@ trait ContextErrors {
setError(tree)
}
+ def MacroEtaError(tree: Tree) = {
+ issueNormalTypeError(tree, "macros cannot be eta-expanded")
+ setError(tree)
+ }
+
//typedReturn
def ReturnOutsideOfDefError(tree: Tree) = {
issueNormalTypeError(tree, "return outside method definition")
@@ -453,6 +453,9 @@ trait ContextErrors {
// doTypeApply
//tryNamesDefaults
+ def NamedAndDefaultArgumentsNotSupportedForMacros(tree: Tree, fun: Tree) =
+ NormalTypeError(tree, "macros application do not support named and/or default arguments")
+
def WrongNumberOfArgsError(tree: Tree, fun: Tree) =
NormalTypeError(tree, "wrong number of arguments for "+ treeSymTypeMsg(fun))
@@ -581,9 +584,9 @@ trait ContextErrors {
def AbstractExistentiallyOverParamerizedTpeError(tree: Tree, tp: Type) =
issueNormalTypeError(tree, "can't existentially abstract over parameterized type " + tp)
- //manifestTreee
- def MissingManifestError(tree: Tree, full: Boolean, tp: Type) = {
- issueNormalTypeError(tree, "cannot find "+(if (full) "" else "class ")+"manifest for element type "+tp)
+ // classTagTree
+ def MissingClassTagError(tree: Tree, tp: Type) = {
+ issueNormalTypeError(tree, "cannot find class tag for element type "+tp)
setError(tree)
}
@@ -622,7 +625,6 @@ trait ContextErrors {
def DefDefinedTwiceError(sym0: Symbol, sym1: Symbol) = {
val isBug = sym0.isAbstractType && sym1.isAbstractType && (sym0.name startsWith "_$")
issueSymbolTypeError(sym0, sym1+" is defined twice in " + context0.unit
- + ( if (sym0.isMacro && sym1.isMacro) "\n(note that macros cannot be overloaded)" else "" )
+ ( if (isBug) "\n(this error is likely due to a bug in the scala compiler involving wildcards in package objects)" else "" )
)
}
@@ -661,7 +663,7 @@ trait ContextErrors {
}
private def ambiguousErrorMsgPos(pos: Position, pre: Type, sym1: Symbol, sym2: Symbol, rest: String) =
- if (sym1.hasDefaultFlag && sym2.hasDefaultFlag && sym1.enclClass == sym2.enclClass) {
+ if (sym1.hasDefault && sym2.hasDefault && sym1.enclClass == sym2.enclClass) {
val methodName = nme.defaultGetterToMethod(sym1.name)
(sym1.enclClass.pos,
"in "+ sym1.enclClass +", multiple overloaded alternatives of " + methodName +
@@ -832,7 +834,7 @@ trait ContextErrors {
implicit val context0 = context
object SymValidateErrors extends Enumeration {
- val ImplicitConstr, ImplicitNotTerm, ImplicitTopObject,
+ val ImplicitConstr, ImplicitNotTermOrClass, ImplicitAtToplevel,
OverrideClass, SealedNonClass, AbstractNonClass,
OverrideConstr, AbstractOverride, LazyAndEarlyInit,
ByNameParameter, AbstractVar = Value
@@ -848,6 +850,19 @@ trait ContextErrors {
def TypeSigError(tree: Tree, ex: TypeError) = {
ex match {
+ case CyclicReference(_, _) if tree.symbol.isTermMacro =>
+ // say, we have a macro def `foo` and its macro impl `impl`
+ // if impl: 1) omits return type, 2) has anything implicit in its body, 3) sees foo
+ //
+ // then implicit search will trigger an error
+ // (note that this is not a compilation error, it's an artifact of implicit search algorithm)
+ // normally, such "errors" are discarded by `isCyclicOrErroneous` in Implicits.scala
+ // but in our case this won't work, because isCyclicOrErroneous catches CyclicReference exceptions
+ // while our error will manifest itself as a "recursive method needs a return type"
+ //
+ // hence we (together with reportTypeError in TypeDiagnostics) make sure that this CyclicReference
+ // evades all the handlers on its way and successfully reaches `isCyclicOrErroneous` in Implicits
+ throw ex
case CyclicReference(sym, info: TypeCompleter) =>
issueNormalTypeError(tree, typer.cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage())
case _ =>
@@ -898,10 +913,10 @@ trait ContextErrors {
case ImplicitConstr =>
"`implicit' modifier not allowed for constructors"
- case ImplicitNotTerm =>
- "`implicit' modifier can be used only for values, variables and methods"
+ case ImplicitNotTermOrClass =>
+ "`implicit' modifier can be used only for values, variables, methods and classes"
- case ImplicitTopObject =>
+ case ImplicitAtToplevel =>
"`implicit' modifier cannot be used for top-level objects"
case OverrideClass =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index a1ba8a2982..fe1c90fe67 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -105,8 +105,8 @@ trait Contexts { self: Analyzer =>
// not inherited to child contexts
var depth: Int = 0
var imports: List[ImportInfo] = List() // currently visible imports
- var openImplicits: List[(Type,Symbol)] = List() // types for which implicit arguments
- // are currently searched
+ var openImplicits: List[(Type,Tree)] = List() // types for which implicit arguments
+ // are currently searched
// for a named application block (Tree) the corresponding NamedApplyInfo
var namedApplyBlockInfo: Option[(Tree, NamedApplyInfo)] = None
var prefix: Type = NoPrefix
@@ -119,6 +119,7 @@ trait Contexts { self: Analyzer =>
var diagnostic: List[String] = Nil // these messages are printed when issuing an error
var implicitsEnabled = false
+ var macrosEnabled = true
var checking = false
var retyping = false
@@ -181,6 +182,13 @@ trait Contexts { self: Analyzer =>
def logError(err: AbsTypeError) = buffer += err
+ def withImplicitsEnabled[T](op: => T): T = {
+ val saved = implicitsEnabled
+ implicitsEnabled = true
+ try op
+ finally implicitsEnabled = saved
+ }
+
def withImplicitsDisabled[T](op: => T): T = {
val saved = implicitsEnabled
implicitsEnabled = false
@@ -188,6 +196,20 @@ trait Contexts { self: Analyzer =>
finally implicitsEnabled = saved
}
+ def withMacrosEnabled[T](op: => T): T = {
+ val saved = macrosEnabled
+ macrosEnabled = true
+ try op
+ finally macrosEnabled = saved
+ }
+
+ def withMacrosDisabled[T](op: => T): T = {
+ val saved = macrosEnabled
+ macrosEnabled = false
+ try op
+ finally macrosEnabled = saved
+ }
+
def make(unit: CompilationUnit, tree: Tree, owner: Symbol,
scope: Scope, imports: List[ImportInfo]): Context = {
val c = new Context
@@ -223,6 +245,7 @@ trait Contexts { self: Analyzer =>
c.diagnostic = this.diagnostic
c.typingIndentLevel = typingIndentLevel
c.implicitsEnabled = this.implicitsEnabled
+ c.macrosEnabled = this.macrosEnabled
c.checking = this.checking
c.retyping = this.retyping
c.openImplicits = this.openImplicits
@@ -237,6 +260,7 @@ trait Contexts { self: Analyzer =>
val c = make(unit, EmptyTree, owner, scope, imports)
c.setReportErrors()
c.implicitsEnabled = true
+ c.macrosEnabled = true
c
}
@@ -312,6 +336,7 @@ trait Contexts { self: Analyzer =>
def issue(err: AbsTypeError) {
debugwarn("issue error: " + err.errMsg)
+ if (settings.Yissuedebug.value) (new Exception).printStackTrace()
if (reportErrors) unitError(err.errPos, addDiagString(err.errMsg))
else if (bufferErrors) { buffer += err }
else throw new TypeError(err.errPos, err.errMsg)
@@ -319,6 +344,7 @@ trait Contexts { self: Analyzer =>
def issueAmbiguousError(pre: Type, sym1: Symbol, sym2: Symbol, err: AbsTypeError) {
debugwarn("issue ambiguous error: " + err.errMsg)
+ if (settings.Yissuedebug.value) (new Exception).printStackTrace()
if (ambiguousErrors) {
if (!pre.isErroneous && !sym1.isErroneous && !sym2.isErroneous)
unitError(err.errPos, err.errMsg)
@@ -328,6 +354,7 @@ trait Contexts { self: Analyzer =>
def issueAmbiguousError(err: AbsTypeError) {
debugwarn("issue ambiguous error: " + err.errMsg)
+ if (settings.Yissuedebug.value) (new Exception).printStackTrace()
if (ambiguousErrors)
unitError(err.errPos, addDiagString(err.errMsg))
else if (bufferErrors) { buffer += err }
@@ -664,7 +691,7 @@ trait Contexts { self: Analyzer =>
case List(ImportSelector(nme.WILDCARD, _, _, _)) => List(sym)
case ImportSelector(from, _, to, _) :: _ if from == sym.name =>
if (to == nme.WILDCARD) List()
- else { val sym1 = sym.cloneSymbol; sym1.name = to; List(sym1) }
+ else List(sym.cloneSymbol(sym.owner, sym.rawflags, to))
case _ :: rest => transformImport(rest, sym)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 7d1198a4a2..3a789b83b6 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -32,7 +32,10 @@ trait Implicits {
import global.typer.{ printTyping, deindentTyping, indentTyping, printInference }
def inferImplicit(tree: Tree, pt: Type, reportAmbiguous: Boolean, isView: Boolean, context: Context): SearchResult =
- inferImplicit(tree, pt, reportAmbiguous, isView, context, true)
+ inferImplicit(tree, pt, reportAmbiguous, isView, context, true, NoPosition)
+
+ def inferImplicit(tree: Tree, pt: Type, reportAmbiguous: Boolean, isView: Boolean, context: Context, saveAmbiguousDivergent: Boolean): SearchResult =
+ inferImplicit(tree, pt, reportAmbiguous, isView, context, saveAmbiguousDivergent, NoPosition)
/** Search for an implicit value. See the comment on `result` at the end of class `ImplicitSearch`
* for more info how the search is conducted.
@@ -48,9 +51,12 @@ trait Implicits {
* @param saveAmbiguousDivergent False if any divergent/ambiguous errors should be ignored after
* implicits search,
* true if they should be reported (used in further typechecking).
+ * @param pos Position that is should be used for tracing and error reporting
+ * (useful when we infer synthetic stuff and pass EmptyTree in the `tree` argument)
+ * If it's set NoPosition, then position-based services will use `tree.pos`
* @return A search result
*/
- def inferImplicit(tree: Tree, pt: Type, reportAmbiguous: Boolean, isView: Boolean, context: Context, saveAmbiguousDivergent: Boolean): SearchResult = {
+ def inferImplicit(tree: Tree, pt: Type, reportAmbiguous: Boolean, isView: Boolean, context: Context, saveAmbiguousDivergent: Boolean, pos: Position): SearchResult = {
printInference("[infer %s] %s with pt=%s in %s".format(
if (isView) "view" else "implicit",
tree, pt, context.owner.enclClass)
@@ -71,9 +77,11 @@ trait Implicits {
if (printInfers && !tree.isEmpty && !context.undetparams.isEmpty)
printTyping("typing implicit: %s %s".format(tree, context.undetparamsString))
val implicitSearchContext = context.makeImplicit(reportAmbiguous)
- val result = new ImplicitSearch(tree, pt, isView, implicitSearchContext).bestImplicit
- if (saveAmbiguousDivergent && implicitSearchContext.hasErrors)
+ val result = new ImplicitSearch(tree, pt, isView, implicitSearchContext, pos).bestImplicit
+ if (saveAmbiguousDivergent && implicitSearchContext.hasErrors) {
context.updateBuffer(implicitSearchContext.errBuffer.filter(err => err.kind == ErrorKinds.Ambiguous || err.kind == ErrorKinds.Divergent))
+ debugwarn("update buffer: " + implicitSearchContext.errBuffer)
+ }
printInference("[infer implicit] inferred " + result)
context.undetparams = context.undetparams filterNot result.subst.from.contains
@@ -100,8 +108,6 @@ trait Implicits {
improvesCache.clear()
}
- private val ManifestSymbols = Set(PartialManifestClass, FullManifestClass, OptManifestClass)
-
/* Map a polytype to one in which all type parameters and argument-dependent types are replaced by wildcards.
* Consider `implicit def b(implicit x: A): x.T = error("")`. We need to approximate DebruijnIndex types
* when checking whether `b` is a valid implicit, as we haven't even searched a value for the implicit arg `x`,
@@ -251,8 +257,11 @@ trait Implicits {
* @param pt The original expected type of the implicit.
* @param isView We are looking for a view
* @param context0 The context used for the implicit search
+ * @param pos0 Position that is preferable for use in tracing and error reporting
+ * (useful when we infer synthetic stuff and pass EmptyTree in the `tree` argument)
+ * If it's set to NoPosition, then position-based services will use `tree.pos`
*/
- class ImplicitSearch(tree: Tree, pt: Type, isView: Boolean, context0: Context)
+ class ImplicitSearch(tree: Tree, pt: Type, isView: Boolean, context0: Context, pos0: Position = NoPosition)
extends Typer(context0) with ImplicitsContextErrors {
printTyping(
ptBlock("new ImplicitSearch",
@@ -264,6 +273,13 @@ trait Implicits {
)
)
// assert(tree.isEmpty || tree.pos.isDefined, tree)
+ def pos = if (pos0 != NoPosition) pos0 else tree.pos
+
+ def failure(what: Any, reason: String, pos: Position = this.pos): SearchResult = {
+ if (settings.XlogImplicits.value)
+ reporter.echo(pos, what+" is not a valid implicit value for "+pt+" because:\n"+reason)
+ SearchFailure
+ }
import infer._
/** Is implicit info `info1` better than implicit info `info2`?
@@ -351,13 +367,13 @@ trait Implicits {
* @pre `info.tpe` does not contain an error
*/
private def typedImplicit(info: ImplicitInfo, ptChecked: Boolean): SearchResult = {
- (context.openImplicits find { case (tp, sym) => sym == tree.symbol && dominates(pt, tp)}) match {
+ (context.openImplicits find { case (tp, tree1) => tree1.symbol == tree.symbol && dominates(pt, tp)}) match {
case Some(pending) =>
// println("Pending implicit "+pending+" dominates "+pt+"/"+undetParams) //@MDEBUG
throw DivergentImplicit
case None =>
try {
- context.openImplicits = (pt, tree.symbol) :: context.openImplicits
+ context.openImplicits = (pt, tree) :: context.openImplicits
// println(" "*context.openImplicits.length+"typed implicit "+info+" for "+pt) //@MDEBUG
typedImplicit0(info, ptChecked)
} catch {
@@ -515,7 +531,7 @@ trait Implicits {
private def typedImplicit1(info: ImplicitInfo): SearchResult = {
incCounter(matchingImplicits)
- val itree = atPos(tree.pos.focus) {
+ val itree = atPos(pos.focus) {
if (info.pre == NoPrefix) Ident(info.name)
else Select(gen.mkAttributedQualifier(info.pre), info.name)
}
@@ -523,11 +539,7 @@ trait Implicits {
typeDebug.ptTree(itree), wildPt, info.name, info.tpe)
)
- def fail(reason: String): SearchResult = {
- if (settings.XlogImplicits.value)
- inform(itree+" is not a valid implicit value for "+pt+" because:\n"+reason)
- SearchFailure
- }
+ def fail(reason: String): SearchResult = failure(itree, reason)
try {
val itree1 =
if (isView) {
@@ -707,6 +719,7 @@ trait Implicits {
info.isCyclicOrErroneous
|| isView && isPredefMemberNamed(info.sym, nme.conforms)
|| isShadowed(info.name)
+ || (!context.macrosEnabled && info.sym.isTermMacro)
)
/** True if a given ImplicitInfo (already known isValid) is eligible.
@@ -825,7 +838,7 @@ trait Implicits {
throw DivergentImplicit
if (invalidImplicits.nonEmpty)
- setAddendum(tree.pos, () =>
+ setAddendum(pos, () =>
"\n Note: implicit "+invalidImplicits.head+" is not applicable here"+
" because it comes after the application point and it lacks an explicit result type")
}
@@ -1085,111 +1098,58 @@ trait Implicits {
implicitInfoss1
}
- /** Creates a tree that calls the relevant factory method in object
- * reflect.Manifest for type 'tp'. An EmptyTree is returned if
- * no manifest is found. todo: make this instantiate take type params as well?
- */
- private def manifestOfType(tp: Type, full: Boolean): SearchResult = {
-
- /** Creates a tree that calls the factory method called constructor in object reflect.Manifest */
- def manifestFactoryCall(constructor: String, tparg: Type, args: Tree*): Tree =
- if (args contains EmptyTree) EmptyTree
- else typedPos(tree.pos.focus) {
- val mani = gen.mkManifestFactoryCall(full, constructor, tparg, args.toList)
- if (settings.debug.value) println("generated manifest: "+mani) // DEBUG
- mani
- }
+ // these should be lazy, otherwise we wouldn't be able to compile scala-library with starr
+ private val TagSymbols = Set(ClassTagClass, TypeTagClass, ConcreteTypeTagClass)
+ private val TagMaterializers = Map(
+ ClassTagClass -> MacroInternal_materializeClassTag,
+ TypeTagClass -> MacroInternal_materializeTypeTag,
+ ConcreteTypeTagClass -> MacroInternal_materializeConcreteTypeTag
+ )
- /** Creates a tree representing one of the singleton manifests.*/
- def findSingletonManifest(name: String) = typedPos(tree.pos.focus) {
- Select(gen.mkAttributedRef(FullManifestModule), name)
- }
+ def tagOfType(pre: Type, tp: Type, tagClass: Symbol): SearchResult = {
+ def success(arg: Tree) =
+ try {
+ val tree1 = typed(atPos(pos.focus)(arg))
+ def isErroneous = tree exists (_.isErroneous)
+ if (context.hasErrors) failure(tp, "failed to typecheck the materialized typetag: %n%s".format(context.errBuffer.head.errMsg), context.errBuffer.head.errPos)
+ else new SearchResult(tree1, EmptyTreeTypeSubstituter)
+ } catch {
+ case ex: TypeError =>
+ failure(arg, "failed to typecheck the materialized typetag: %n%s".format(ex.msg), ex.pos)
+ }
- /** Re-wraps a type in a manifest before calling inferImplicit on the result */
- def findManifest(tp: Type, manifestClass: Symbol = if (full) FullManifestClass else PartialManifestClass) =
- inferImplicit(tree, appliedType(manifestClass.typeConstructor, List(tp)), true, false, context).tree
-
- def findSubManifest(tp: Type) = findManifest(tp, if (full) FullManifestClass else OptManifestClass)
- def mot(tp0: Type, from: List[Symbol], to: List[Type]): SearchResult = {
- implicit def wrapResult(tree: Tree): SearchResult =
- if (tree == EmptyTree) SearchFailure else new SearchResult(tree, if (from.isEmpty) EmptyTreeTypeSubstituter else new TreeTypeSubstituter(from, to))
-
- val tp1 = tp0.normalize
- tp1 match {
- case ThisType(_) | SingleType(_, _) =>
- // can't generate a reference to a value that's abstracted over by an existential
- if (containsExistential(tp1)) EmptyTree
- else manifestFactoryCall("singleType", tp, gen.mkAttributedQualifier(tp1))
- case ConstantType(value) =>
- manifestOfType(tp1.deconst, full)
- case TypeRef(pre, sym, args) =>
- if (isPrimitiveValueClass(sym) || isPhantomClass(sym)) {
- findSingletonManifest(sym.name.toString)
- } else if (sym == ObjectClass || sym == AnyRefClass) {
- findSingletonManifest("Object")
- } else if (sym == RepeatedParamClass || sym == ByNameParamClass) {
- EmptyTree
- } else if (sym == ArrayClass && args.length == 1) {
- manifestFactoryCall("arrayType", args.head, findManifest(args.head))
- } else if (sym.isClass) {
- val classarg0 = gen.mkClassOf(tp1)
- val classarg = tp match {
- case _: ExistentialType => gen.mkCast(classarg0, ClassType(tp))
- case _ => classarg0
- }
- val suffix = classarg :: (args map findSubManifest)
- manifestFactoryCall(
- "classType", tp,
- (if ((pre eq NoPrefix) || pre.typeSymbol.isStaticOwner) suffix
- else findSubManifest(pre) :: suffix): _*)
- } else if (sym.isExistentiallyBound && full) {
- manifestFactoryCall("wildcardType", tp,
- findManifest(tp.bounds.lo), findManifest(tp.bounds.hi))
- }
- // looking for a manifest of a type parameter that hasn't been inferred by now,
- // can't do much, but let's not fail
- else if (undetParams contains sym) {
- // #3859: need to include the mapping from sym -> NothingClass.tpe in the SearchResult
- mot(NothingClass.tpe, sym :: from, NothingClass.tpe :: to)
- } else {
- // a manifest should have been found by normal searchImplicit
- EmptyTree
- }
- case RefinedType(parents, decls) => // !!! not yet: if !full || decls.isEmpty =>
- // refinement is not generated yet
- if (hasLength(parents, 1)) findManifest(parents.head)
- else if (full) manifestFactoryCall("intersectionType", tp, parents map findSubManifest: _*)
- else mot(erasure.intersectionDominator(parents), from, to)
- case ExistentialType(tparams, result) =>
- mot(tp1.skolemizeExistential, from, to)
- case _ =>
- EmptyTree
-/* !!! the following is almost right, but we have to splice nested manifest
- * !!! types into this type. This requires a substantial extension of
- * !!! reifiers.
- val reifier = new Reifier()
- val rtree = reifier.reifyTopLevel(tp1)
- manifestFactoryCall("apply", tp, rtree)
-*/
- }
+ val prefix = (tagClass, pre) match {
+ // ClassTags only exist for scala.reflect.mirror, so their materializer doesn't care about prefixes
+ case (ClassTagClass, _) =>
+ gen.mkAttributedRef(Reflect_mirror) setType singleType(Reflect_mirror.owner.thisPrefix, Reflect_mirror)
+ // [Eugene to Martin] this is the crux of the interaction between implicits and reifiers
+ // here we need to turn a (supposedly path-dependent) type into a tree that will be used as a prefix
+ // I'm not sure if I've done this right - please, review
+ case (_, SingleType(prePre, preSym)) =>
+ gen.mkAttributedRef(prePre, preSym) setType pre
+ // necessary only to compile typetags used inside the Universe cake
+ case (_, ThisType(thisSym)) =>
+ gen.mkAttributedThis(thisSym)
+ case _ =>
+ // if ``pre'' is not a PDT, e.g. if someone wrote
+ // implicitly[scala.reflect.makro.Context#TypeTag[Int]]
+ // then we need to fail, because we don't know the prefix to use during type reification
+ return failure(tp, "tag error: unsupported prefix type %s (%s)".format(pre, pre.kind))
}
- mot(tp, Nil, Nil)
+ // todo. migrate hardcoded materialization in Implicits to corresponding implicit macros
+ var materializer = atPos(pos.focus)(Apply(TypeApply(Ident(TagMaterializers(tagClass)), List(TypeTree(tp))), List(prefix)))
+ if (settings.XlogImplicits.value) println("materializing requested %s.%s[%s] using %s".format(pre, tagClass.name, tp, materializer))
+ success(materializer)
}
- def wrapResult(tree: Tree): SearchResult =
- if (tree == EmptyTree) SearchFailure else new SearchResult(tree, EmptyTreeTypeSubstituter)
-
/** The manifest corresponding to type `pt`, provided `pt` is an instance of Manifest.
*/
- private def implicitManifestOrOfExpectedType(pt: Type): SearchResult = pt.dealias match {
- case TypeRef(_, sym, args) if ManifestSymbols(sym) =>
- manifestOfType(args.head, sym == FullManifestClass) match {
- case SearchFailure if sym == OptManifestClass => wrapResult(gen.mkAttributedRef(NoManifest))
- case result => result
- }
+ private def implicitTagOrOfExpectedType(pt: Type): SearchResult = pt.dealias match {
+ case TypeRef(pre, sym, args) if TagSymbols(sym) =>
+ tagOfType(pre, args.head, sym)
case tp@TypeRef(_, sym, _) if sym.isAbstractType =>
- implicitManifestOrOfExpectedType(tp.bounds.lo) // #3977: use tp (==pt.dealias), not pt (if pt is a type alias, pt.bounds.lo == pt)
+ implicitTagOrOfExpectedType(tp.bounds.lo) // #3977: use tp (==pt.dealias), not pt (if pt is a type alias, pt.bounds.lo == pt)
case _ =>
searchImplicit(implicitsOfExpectedType, false)
// shouldn't we pass `pt` to `implicitsOfExpectedType`, or is the recursive case
@@ -1199,7 +1159,9 @@ trait Implicits {
/** The result of the implicit search:
* First search implicits visible in current context.
* If that fails, search implicits in expected type `pt`.
- * If that fails, and `pt` is an instance of Manifest, try to construct a manifest.
+ * // [Eugene] the following two lines should be deleted after we migrate delegate manifest materialization to implicit macros
+ * If that fails, and `pt` is an instance of a ClassTag, try to construct a class tag.
+ * If that fails, and `pt` is an instance of a TypeTag, try to construct a type tag.
* If all fails return SearchFailure
*/
def bestImplicit: SearchResult = {
@@ -1219,7 +1181,7 @@ trait Implicits {
val failstart = startTimer(oftypeFailNanos)
val succstart = startTimer(oftypeSucceedNanos)
- result = implicitManifestOrOfExpectedType(pt)
+ result = implicitTagOrOfExpectedType(pt)
if (result == SearchFailure) {
context.updateBuffer(previousErrs)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index dba31f7bca..98b8d7673e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -67,7 +67,7 @@ trait Infer {
*/
def freshVar(tparam: Symbol): TypeVar = TypeVar(tparam)
- private class NoInstance(msg: String) extends Throwable(msg) with ControlThrowable { }
+ class NoInstance(msg: String) extends Throwable(msg) with ControlThrowable { }
private class DeferredNoInstance(getmsg: () => String) extends NoInstance("") {
override def getMessage(): String = getmsg()
}
@@ -267,6 +267,16 @@ trait Infer {
setError(tree)
}
else {
+ if (context.owner.isTermMacro && (sym1 hasFlag LOCKED)) {
+ // we must not let CyclicReference to be thrown from sym1.info
+ // because that would mark sym1 erroneous, which it is not
+ // but if it's a true CyclicReference then macro def will report it
+ // see comments to TypeSigError for an explanation of this special case
+ // [Eugene] is there a better way?
+ val dummy = new TypeCompleter { val tree = EmptyTree; override def complete(sym: Symbol) {} }
+ throw CyclicReference(sym1, dummy)
+ }
+
if (sym1.isTerm)
sym1.cookJavaRawInfo() // xform java rawtypes into existentials
@@ -310,6 +320,8 @@ trait Infer {
/** Like weakly compatible but don't apply any implicit conversions yet.
* Used when comparing the result type of a method with its prototype.
+ * [Martin] I think Infer is also created by Erasure, with the default
+ * implementation of isCoercible
*/
def isConservativelyCompatible(tp: Type, pt: Type): Boolean =
context.withImplicitsDisabled(isWeaklyCompatible(tp, pt))
@@ -426,6 +438,9 @@ trait Infer {
tvars map (tvar => WildcardType)
}
+ /** [Martin] Can someone comment this please? I have no idea what it's for
+ * and the code is not exactly readable.
+ */
object AdjustedTypeArgs {
val Result = collection.mutable.LinkedHashMap
type Result = collection.mutable.LinkedHashMap[Symbol, Option[Type]]
@@ -699,7 +714,7 @@ trait Infer {
case NamedType(name, _) => Some(name)
case _ => None
})._1
- if (missing forall (_.hasDefaultFlag)) {
+ if (missing forall (_.hasDefault)) {
// add defaults as named arguments
val argtpes1 = argtpes0 ::: (missing map (p => NamedType(p.name, p.tpe)))
isApplicable(undetparams, ftpe, argtpes1, pt)
@@ -992,6 +1007,7 @@ trait Infer {
PolymorphicExpressionInstantiationError(tree, undetparams, pt)
} else {
new TreeTypeSubstituter(undetparams, targs).traverse(tree)
+ notifyUndetparamsInferred(undetparams, targs)
}
}
@@ -1028,6 +1044,7 @@ trait Infer {
if (checkBounds(fn, NoPrefix, NoSymbol, undetparams, allargs, "inferred ")) {
val treeSubst = new TreeTypeSubstituter(okparams, okargs)
treeSubst traverseTrees fn :: args
+ notifyUndetparamsInferred(okparams, okargs)
leftUndet match {
case Nil => Nil
@@ -1116,6 +1133,7 @@ trait Infer {
(inferFor(pt) orElse inferForApproxPt) map { targs =>
new TreeTypeSubstituter(undetparams, targs).traverse(tree)
+ notifyUndetparamsInferred(undetparams, targs)
} getOrElse {
debugwarn("failed inferConstructorInstance for "+ tree +" : "+ tree.tpe +" under "+ undetparams +" pt = "+ pt +(if(isFullyDefined(pt)) " (fully defined)" else " (not fully defined)"))
// if (settings.explaintypes.value) explainTypes(resTp.instantiateTypeParams(undetparams, tvars), pt)
@@ -1568,9 +1586,9 @@ trait Infer {
else infer
}
- /** Assign <code>tree</code> the type of unique polymorphic alternative
+ /** Assign <code>tree</code> the type of all polymorphic alternatives
* with <code>nparams</code> as the number of type parameters, if it exists.
- * If several or none such polymorphic alternatives exist, error.
+ * If no such polymorphic alternative exist, error.
*
* @param tree ...
* @param nparams ...
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index e43b1fab0b..9608108a0d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -3,135 +3,682 @@ package typechecker
import symtab.Flags._
import scala.tools.nsc.util._
+import scala.tools.nsc.util.ClassPath._
import scala.reflect.ReflectionUtils
+import scala.collection.mutable.ListBuffer
+import scala.compat.Platform.EOL
+import scala.reflect.makro.runtime.{Context => MacroContext}
+import scala.reflect.runtime.Mirror
+/**
+ * Code to deal with macros, namely with:
+ * * Compilation of macro definitions
+ * * Expansion of macro applications
+ *
+ * Say we have in a class C:
+ *
+ * def foo[T](xs: List[T]): T = macro fooBar
+ *
+ * Then fooBar needs to point to a static method of the following form:
+ *
+ * def fooBar[T: c.TypeTag]
+ * (c: scala.reflect.makro.Context)
+ * (xs: c.Expr[List[T]])
+ * : c.mirror.Tree = {
+ * ...
+ * }
+ *
+ * Then, if foo is called in qual.foo[Int](elems), where qual: D,
+ * the macro application is expanded to a reflective invocation of fooBar with parameters
+ *
+ * (simpleMacroContext{ type PrefixType = D; val prefix = qual })
+ * (Expr(elems))
+ * (TypeTag(Int))
+ */
trait Macros { self: Analyzer =>
import global._
import definitions._
- def macroMeth(mac: Symbol): Symbol = {
- var owner = mac.owner
- if (!owner.isModuleClass) owner = owner.companionModule.moduleClass
- owner.info.decl(nme.macroMethodName(mac.name))
- }
+ val macroDebug = settings.Ymacrodebug.value
+ val macroCopypaste = settings.Ymacrocopypaste.value
+ val macroTrace = scala.tools.nsc.util.trace when macroDebug
- def macroArgs(tree: Tree): (List[List[Tree]]) = tree match {
- case Apply(fn, args) =>
- macroArgs(fn) :+ args
- case TypeApply(fn, args) =>
- macroArgs(fn) :+ args
- case Select(qual, name) =>
- List(List(qual))
- case _ =>
- List(List())
- }
+ val globalMacroCache = collection.mutable.Map[Any, Any]()
+ val perRunMacroCache = perRunCaches.newMap[Symbol, collection.mutable.Map[Any, Any]]
- /**
- * The definition of the method implementing a macro. Example:
- * Say we have in a class C
+ /** A list of compatible macro implementation signatures.
*
- * def macro foo[T](xs: List[T]): T = expr
+ * In the example above:
+ * (c: scala.reflect.makro.Context)(xs: c.Expr[List[T]]): c.Expr[T]
*
- * Then the following macro method is generated for `foo`:
- *
- * def defmacro$foo
- * (_context: scala.reflect.macro.Context)
- * (_this: _context.Tree)
- * (T: _context.TypeTree)
- * (xs: _context.Tree): _context.Tree = {
- * import _context._ // this means that all methods of Context can be used unqualified in macro's body
- * expr
- * }
+ * @param macroDef The macro definition symbol
+ * @param tparams The type parameters of the macro definition
+ * @param vparamss The value parameters of the macro definition
+ * @param retTpe The return type of the macro definition
+ */
+ private def macroImplSigs(macroDef: Symbol, tparams: List[TypeDef], vparamss: List[List[ValDef]], retTpe: Type): (List[List[List[Symbol]]], Type) = {
+ // had to move method's body to an object because of the recursive dependencies between sigma and param
+ object SigGenerator {
+ val hasThis = macroDef.owner.isClass
+ val ownerTpe = macroDef.owner match {
+ case owner if owner.isModuleClass => new UniqueThisType(macroDef.owner)
+ case owner if owner.isClass => macroDef.owner.tpe
+ case _ => NoType
+ }
+ val hasTparams = !tparams.isEmpty
+
+ def sigma(tpe: Type): Type = {
+ class SigmaTypeMap extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case TypeRef(pre, sym, args) =>
+ val pre1 = pre match {
+ case ThisType(sym) if sym == macroDef.owner =>
+ SingleType(SingleType(SingleType(NoPrefix, paramsCtx(0)), MacroContextPrefix), ExprValue)
+ case SingleType(NoPrefix, sym) =>
+ vparamss.flatten.find(_.symbol == sym) match {
+ case Some(macroDefParam) =>
+ SingleType(SingleType(NoPrefix, param(macroDefParam)), ExprValue)
+ case _ =>
+ pre
+ }
+ case _ =>
+ pre
+ }
+ val args1 = args map mapOver
+ TypeRef(pre1, sym, args1)
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
+ new SigmaTypeMap() apply tpe
+ }
+
+ def makeParam(name: Name, pos: Position, tpe: Type, flags: Long = 0L) =
+ macroDef.newValueParameter(name, pos, flags) setInfo tpe
+ val ctxParam = makeParam(nme.macroContext, macroDef.pos, MacroContextClass.tpe, SYNTHETIC)
+ def implType(isType: Boolean, origTpe: Type): Type =
+ if (isRepeatedParamType(origTpe))
+ appliedType(
+ RepeatedParamClass.typeConstructor,
+ List(implType(isType, sigma(origTpe.typeArgs.head))))
+ else {
+ val tsym = getMember(MacroContextClass, if (isType) tpnme.TypeTag else tpnme.Expr)
+ typeRef(singleType(NoPrefix, ctxParam), tsym, List(sigma(origTpe)))
+ }
+ val paramCache = collection.mutable.Map[Symbol, Symbol]()
+ def param(tree: Tree): Symbol =
+ paramCache.getOrElseUpdate(tree.symbol, {
+ // [Eugene] deskolemization became necessary once I implemented inference of macro def return type
+ // please, verify this solution, but for now I'll leave it here - cargo cult for the win
+ val sym = tree.symbol.deSkolemize
+ val sigParam = makeParam(sym.name, sym.pos, implType(sym.isType, sym.tpe))
+ if (sym.isSynthetic) sigParam.flags |= SYNTHETIC
+ sigParam
+ })
+
+ val paramsCtx = List(ctxParam)
+ val paramsThis = List(makeParam(nme.macroThis, macroDef.pos, implType(false, ownerTpe), SYNTHETIC))
+ val paramsTparams = tparams map param
+ val paramssParams = vparamss map (_ map param)
+
+ var paramsss = List[List[List[Symbol]]]()
+ // tparams are no longer part of a signature, they get into macro implementations via context bounds
+// if (hasTparams && hasThis) paramsss :+= paramsCtx :: paramsThis :: paramsTparams :: paramssParams
+// if (hasTparams) paramsss :+= paramsCtx :: paramsTparams :: paramssParams
+ // _this params are no longer part of a signature, its gets into macro implementations via Context.prefix
+// if (hasThis) paramsss :+= paramsCtx :: paramsThis :: paramssParams
+ paramsss :+= paramsCtx :: paramssParams
+
+ val tsym = getMember(MacroContextClass, tpnme.Expr)
+ val implRetTpe = typeRef(singleType(NoPrefix, ctxParam), tsym, List(sigma(retTpe)))
+ }
+
+ import SigGenerator._
+ macroTrace("generating macroImplSigs for: ")(macroDef)
+ macroTrace("tparams are: ")(tparams)
+ macroTrace("vparamss are: ")(vparamss)
+ macroTrace("retTpe is: ")(retTpe)
+ macroTrace("macroImplSigs are: ")(paramsss, implRetTpe)
+ }
+
+ private def transformTypeTagEvidenceParams(paramss: List[List[Symbol]], transform: (Symbol, Symbol) => Option[Symbol]): List[List[Symbol]] = {
+ if (paramss.length == 0)
+ return paramss
+
+ val wannabe = if (paramss.head.length == 1) paramss.head.head else NoSymbol
+ val contextParam = if (wannabe != NoSymbol && wannabe.tpe <:< definitions.MacroContextClass.tpe) wannabe else NoSymbol
+
+ val lastParamList0 = paramss.lastOption getOrElse Nil
+ val lastParamList = lastParamList0 flatMap (param => param.tpe match {
+ case TypeRef(SingleType(NoPrefix, contextParam), sym, List(tparam)) =>
+ var wannabe = sym
+ while (wannabe.isAliasType) wannabe = wannabe.info.typeSymbol
+ if (wannabe != definitions.TypeTagClass)
+ List(param)
+ else
+ transform(param, tparam.typeSymbol) map (_ :: Nil) getOrElse Nil
+ case _ =>
+ List(param)
+ })
+
+ var result = paramss.dropRight(1) :+ lastParamList
+ if (lastParamList0.isEmpty ^ lastParamList.isEmpty) {
+ result = result dropRight 1
+ }
+
+ result
+ }
+
+ /** As specified above, body of a macro definition must reference its implementation.
+ * This function verifies that the body indeed refers to a method, and that
+ * the referenced macro implementation is compatible with the given macro definition.
*
- * If macro has no type arguments, the third parameter list is omitted (it's not empty, but omitted altogether).
+ * This means that macro implementation (fooBar in example above) must:
+ * 1) Refer to a statically accessible, non-overloaded method.
+ * 2) Have the right parameter lists as outlined in the SIP / in the doc comment of this class.
*
- * To find out the desugared representation of your particular macro, compile it with -Ymacro-debug.
+ * @return typechecked rhs of the given macro definition
*/
- def macroMethDef(mdef: DefDef): Tree = {
- def paramDef(name: Name, tpt: Tree) = ValDef(Modifiers(PARAM), name, tpt, EmptyTree)
- val contextType = TypeTree(ReflectMacroContext.tpe)
- val globParamSec = List(paramDef(nme.macroContext, contextType))
- def globSelect(name: Name) = Select(Ident(nme.macroContext), name)
- def globTree = globSelect(tpnme.Tree)
- def globTypeTree = globSelect(tpnme.TypeTree)
- val thisParamSec = List(paramDef(newTermName(nme.macroThis), globTree))
- def tparamInMacro(tdef: TypeDef) = paramDef(tdef.name.toTermName, globTypeTree)
- def vparamInMacro(vdef: ValDef): ValDef = paramDef(vdef.name, vdef.tpt match {
- case tpt @ AppliedTypeTree(hk, _) if treeInfo.isRepeatedParamType(tpt) => AppliedTypeTree(hk, List(globTree))
- case _ => globTree
- })
- def wrapImplicit(tree: Tree) = atPos(tree.pos) {
- // implicit hasn't proven useful so far, so I'm disabling it
- //val implicitDecl = ValDef(Modifiers(IMPLICIT), nme.macroContextImplicit, SingletonTypeTree(Ident(nme.macroContext)), Ident(nme.macroContext))
- val importGlob = Import(Ident(nme.macroContext), List(ImportSelector(nme.WILDCARD, -1, null, -1)))
- Block(List(importGlob), tree)
+ def typedMacroBody(typer: Typer, ddef: DefDef): Tree = {
+ import typer.context
+ if (macroDebug) println("typechecking macro def %s at %s".format(ddef.symbol, ddef.pos))
+
+ implicit def augmentString(s: String) = new AugmentedString(s)
+ class AugmentedString(s: String) {
+ def abbreviateCoreAliases: String = { // hack!
+ var result = s
+ result = result.replace("c.mirror.TypeTag", "c.TypeTag")
+ result = result.replace("c.mirror.Expr", "c.Expr")
+ result
+ }
}
- var formals = (mdef.vparamss map (_ map vparamInMacro))
- if (mdef.tparams.nonEmpty) formals = (mdef.tparams map tparamInMacro) :: formals
-
- atPos(mdef.pos) {
- new DefDef( // can't call DefDef here; need to find out why
- mods = mdef.mods &~ MACRO &~ OVERRIDE,
- name = nme.macroMethodName(mdef.name),
- tparams = List(),
- vparamss = globParamSec :: thisParamSec :: formals,
- tpt = globTree,
- wrapImplicit(mdef.rhs))
+
+ var hasErrors = false
+ def reportError(pos: Position, msg: String) = {
+ hasErrors = true
+ context.error(pos, msg)
+ }
+
+ val macroDef = ddef.symbol
+ val defpos = macroDef.pos
+ val implpos = ddef.rhs.pos
+ assert(macroDef.isTermMacro, ddef)
+
+ def invalidBodyError() =
+ reportError(defpos,
+ "macro body has wrong shape:" +
+ "\n required: macro <reference to implementation object>.<implementation method name>" +
+ "\n or : macro <implementation method name>")
+ def validatePreTyper(rhs: Tree): Unit = rhs match {
+ // we do allow macro invocations inside macro bodies
+ // personally I don't mind if pre-typer tree is a macro invocation
+ // that later resolves to a valid reference to a macro implementation
+ // however, I don't think that invalidBodyError() should hint at that
+ // let this be an Easter Egg :)
+ case Apply(_, _) => ;
+ case TypeApply(_, _) => ;
+ case Super(_, _) => ;
+ case This(_) => ;
+ case Ident(_) => ;
+ case Select(_, _) => ;
+ case _ => invalidBodyError()
}
+ def validatePostTyper(rhs1: Tree): Unit = {
+ def loop(tree: Tree): Unit = {
+ def errorNotStatic() =
+ reportError(implpos, "macro implementation must be in statically accessible object")
+
+ def ensureRoot(sym: Symbol) =
+ if (!sym.isModule && !sym.isModuleClass) errorNotStatic()
+
+ def ensureModule(sym: Symbol) =
+ if (!sym.isModule) errorNotStatic()
+
+ tree match {
+ case TypeApply(fun, _) =>
+ loop(fun)
+ case Super(qual, _) =>
+ ensureRoot(macroDef.owner)
+ loop(qual)
+ case This(_) =>
+ ensureRoot(tree.symbol)
+ case Select(qual, name) if name.isTypeName =>
+ loop(qual)
+ case Select(qual, name) if name.isTermName =>
+ if (tree.symbol != rhs1.symbol) ensureModule(tree.symbol)
+ loop(qual)
+ case Ident(name) if name.isTypeName =>
+ ;
+ case Ident(name) if name.isTermName =>
+ if (tree.symbol != rhs1.symbol) ensureModule(tree.symbol)
+ case _ =>
+ invalidBodyError()
+ }
+ }
+
+ loop(rhs1)
+ }
+
+ val rhs = ddef.rhs
+ validatePreTyper(rhs)
+ if (hasErrors) macroTrace("macro def failed to satisfy trivial preconditions: ")(macroDef)
+
+ // we use typed1 instead of typed, because otherwise adapt is going to mess us up
+ // if adapt sees <qualifier>.<method>, it will want to perform eta-expansion and will fail
+ // unfortunately, this means that we have to manually trigger macro expansion
+ // because it's adapt which is responsible for automatic expansion during typechecking
+ def typecheckRhs(rhs: Tree): Tree = {
+ try {
+ val prevNumErrors = reporter.ERROR.count // [Eugene] funnily enough, the isErroneous check is not enough
+ var rhs1 = if (hasErrors) EmptyTree else typer.typed1(rhs, EXPRmode, WildcardType)
+ def typecheckedWithErrors = (rhs1 exists (_.isErroneous)) || reporter.ERROR.count != prevNumErrors
+ def rhsNeedsMacroExpansion = rhs1.symbol != null && rhs1.symbol.isTermMacro && !rhs1.symbol.isErroneous
+ while (!typecheckedWithErrors && rhsNeedsMacroExpansion) {
+ rhs1 = macroExpand1(typer, rhs1) match {
+ case Success(expanded) =>
+ try {
+ val typechecked = typer.typed1(expanded, EXPRmode, WildcardType)
+ if (macroDebug) {
+ println("typechecked1:")
+ println(typechecked)
+ println(showRaw(typechecked))
+ }
+
+ typechecked
+ } finally {
+ openMacros = openMacros.tail
+ }
+ case Fallback(fallback) =>
+ typer.typed1(fallback, EXPRmode, WildcardType)
+ case Other(result) =>
+ result
+ }
+ }
+ rhs1
+ } catch {
+ case ex: TypeError =>
+ typer.reportTypeError(context, rhs.pos, ex)
+ typer.infer.setError(rhs)
+ }
+ }
+
+ val prevNumErrors = reporter.ERROR.count // funnily enough, the isErroneous check is not enough
+ var rhs1 = typecheckRhs(rhs)
+ def typecheckedWithErrors = (rhs1 exists (_.isErroneous)) || reporter.ERROR.count != prevNumErrors
+ hasErrors = hasErrors || typecheckedWithErrors
+ if (typecheckedWithErrors) macroTrace("body of a macro def failed to typecheck: ")(ddef)
+
+ val macroImpl = rhs1.symbol
+ macroDef withAnnotation AnnotationInfo(MacroImplAnnotation.tpe, List(rhs1), Nil)
+ if (!hasErrors) {
+ if (macroImpl == null) {
+ invalidBodyError()
+ } else {
+ if (!macroImpl.isMethod)
+ invalidBodyError()
+ if (macroImpl.isOverloaded)
+ reportError(implpos, "macro implementation cannot be overloaded")
+ if (!macroImpl.typeParams.isEmpty && (!rhs1.isInstanceOf[TypeApply]))
+ reportError(implpos, "macro implementation reference needs type arguments")
+ if (!hasErrors)
+ validatePostTyper(rhs1)
+ }
+ if (hasErrors)
+ macroTrace("macro def failed to satisfy trivial preconditions: ")(macroDef)
+ }
+
+ if (!hasErrors) {
+ def checkCompatibility(reqparamss: List[List[Symbol]], actparamss: List[List[Symbol]], reqres: Type, actres: Type): List[String] = {
+ var hasErrors = false
+ var errors = List[String]()
+ def compatibilityError(msg: String) {
+ hasErrors = true
+ errors :+= msg
+ }
+
+ val flatreqparams = reqparamss.flatten
+ val flatactparams = actparamss.flatten
+ val tparams = macroImpl.typeParams
+ val tvars = tparams map freshVar
+ def lengthMsg(which: String, extra: Symbol) =
+ "parameter lists have different length, "+which+" extra parameter "+extra.defString
+ if (actparamss.length != reqparamss.length)
+ compatibilityError("number of parameter sections differ")
+
+ if (!hasErrors) {
+ try {
+ for ((rparams, aparams) <- reqparamss zip actparamss) {
+ if (rparams.length < aparams.length)
+ compatibilityError(lengthMsg("found", aparams(rparams.length)))
+ if (aparams.length < rparams.length)
+ compatibilityError(lengthMsg("required", rparams(aparams.length)).abbreviateCoreAliases)
+ }
+ // if the implementation signature is already deemed to be incompatible, we bail out
+ // otherwise, high-order type magic employed below might crash in weird ways
+ if (!hasErrors) {
+ for ((rparams, aparams) <- reqparamss zip actparamss) {
+ for ((rparam, aparam) <- rparams zip aparams) {
+ def isRepeated(param: Symbol) = param.tpe.typeSymbol == RepeatedParamClass
+ if (rparam.name != aparam.name && !rparam.isSynthetic) {
+ val rparam1 = rparam
+ val aparam1 = aparam
+ compatibilityError("parameter names differ: "+rparam.name+" != "+aparam.name)
+ }
+ if (isRepeated(rparam) && !isRepeated(aparam))
+ compatibilityError("types incompatible for parameter "+rparam.name+": corresponding is not a vararg parameter")
+ if (!isRepeated(rparam) && isRepeated(aparam))
+ compatibilityError("types incompatible for parameter "+aparam.name+": corresponding is not a vararg parameter")
+ if (!hasErrors) {
+ var atpe = aparam.tpe.substSym(flatactparams, flatreqparams).instantiateTypeParams(tparams, tvars)
+
+ // strip the { type PrefixType = ... } refinement off the Context or otherwise we get compatibility errors
+ atpe = atpe match {
+ case RefinedType(List(tpe), Scope(sym)) if tpe == MacroContextClass.tpe && sym.allOverriddenSymbols.contains(MacroContextPrefixType) => tpe
+ case _ => atpe
+ }
+
+ val ok = if (macroDebug) withTypesExplained(rparam.tpe <:< atpe) else rparam.tpe <:< atpe
+ if (!ok) {
+ compatibilityError("type mismatch for parameter "+rparam.name+": "+rparam.tpe.toString.abbreviateCoreAliases+" does not conform to "+atpe)
+ }
+ }
+ }
+ }
+ }
+ if (!hasErrors) {
+ val atpe = actres.substSym(flatactparams, flatreqparams).instantiateTypeParams(tparams, tvars)
+ val ok = if (macroDebug) withTypesExplained(atpe <:< reqres) else atpe <:< reqres
+ if (!ok) {
+ compatibilityError("type mismatch for return type : "+reqres.toString.abbreviateCoreAliases+" does not conform to "+(if (ddef.tpt.tpe != null) atpe.toString else atpe.toString.abbreviateCoreAliases))
+ }
+ }
+ if (!hasErrors) {
+ val targs = solvedTypes(tvars, tparams, tparams map varianceInType(actres), false,
+ lubDepth(flatactparams map (_.tpe)) max lubDepth(flatreqparams map (_.tpe)))
+ val boundsOk = typer.silent(_.infer.checkBounds(ddef, NoPrefix, NoSymbol, tparams, targs, ""))
+ boundsOk match {
+ case SilentResultValue(true) => ;
+ case SilentResultValue(false) | SilentTypeError(_) =>
+ val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, targs).bounds)
+ compatibilityError("type arguments " + targs.mkString("[", ",", "]") +
+ " do not conform to " + tparams.head.owner + "'s type parameter bounds " +
+ (tparams map (_.defString)).mkString("[", ",", "]"))
+ }
+ }
+ } catch {
+ case ex: NoInstance =>
+ compatibilityError(
+ "type parameters "+(tparams map (_.defString) mkString ", ")+" cannot be instantiated\n"+
+ ex.getMessage)
+ }
+ }
+
+ errors.toList
+ }
+
+ var actparamss = macroImpl.paramss
+ actparamss = transformTypeTagEvidenceParams(actparamss, (param, tparam) => None)
+
+ val rettpe = if (ddef.tpt.tpe != null) ddef.tpt.tpe else computeMacroDefTypeFromMacroImpl(ddef, macroDef, macroImpl)
+ val (reqparamsss0, reqres0) = macroImplSigs(macroDef, ddef.tparams, ddef.vparamss, rettpe)
+ var reqparamsss = reqparamsss0
+
+ // prohibit implicit params on macro implementations
+ // we don't have to do this, but it appears to be more clear than allowing them
+ val implicitParams = actparamss.flatten filter (_.isImplicit)
+ if (implicitParams.length > 0) {
+ reportError(implicitParams.head.pos, "macro implementations cannot have implicit parameters other than TypeTag evidences")
+ macroTrace("macro def failed to satisfy trivial preconditions: ")(macroDef)
+ }
+
+ if (!hasErrors) {
+ val reqres = reqres0
+ val actres = macroImpl.tpe.finalResultType
+ def showMeth(pss: List[List[Symbol]], restpe: Type, abbreviate: Boolean) = {
+ var argsPart = (pss map (ps => ps map (_.defString) mkString ("(", ", ", ")"))).mkString
+ if (abbreviate) argsPart = argsPart.abbreviateCoreAliases
+ var retPart = restpe.toString
+ if (abbreviate || ddef.tpt.tpe == null) retPart = retPart.abbreviateCoreAliases
+ argsPart + ": " + retPart
+ }
+ def compatibilityError(addendum: String) =
+ reportError(implpos,
+ "macro implementation has wrong shape:"+
+ "\n required: "+showMeth(reqparamsss.head, reqres, true) +
+ (reqparamsss.tail map (paramss => "\n or : "+showMeth(paramss, reqres, true)) mkString "")+
+ "\n found : "+showMeth(actparamss, actres, false)+
+ "\n"+addendum)
+
+ macroTrace("considering " + reqparamsss.length + " possibilities of compatible macro impl signatures for macro def: ")(ddef.name)
+ val results = reqparamsss map (checkCompatibility(_, actparamss, reqres, actres))
+ if (macroDebug) (reqparamsss zip results) foreach { case (reqparamss, result) =>
+ println("%s %s".format(if (result.isEmpty) "[ OK ]" else "[FAILED]", reqparamss))
+ result foreach (errorMsg => println(" " + errorMsg))
+ }
+
+ if (results forall (!_.isEmpty)) {
+ var index = reqparamsss indexWhere (_.length == actparamss.length)
+ if (index == -1) index = 0
+ val mostRelevantMessage = results(index).head
+ compatibilityError(mostRelevantMessage)
+ } else {
+ assert((results filter (_.isEmpty)).length == 1, results)
+ if (macroDebug) (reqparamsss zip results) filter (_._2.isEmpty) foreach { case (reqparamss, result) =>
+ println("typechecked macro impl as: " + reqparamss)
+ }
+ }
+ }
+ }
+
+ // if this macro definition is erroneous, then there's no sense in expanding its usages
+ // in the previous prototype macro implementations were magically generated from macro definitions
+ // so macro definitions and its usages couldn't be compiled in the same compilation run
+ // however, now definitions and implementations are decoupled, so it's everything is possible
+ // hence, we now use IS_ERROR flag to serve as an indicator that given macro definition is broken
+ if (hasErrors) {
+ macroDef setFlag IS_ERROR
+ }
+
+ rhs1
}
- def addMacroMethods(templ: Template, namer: Namer): Unit = {
- for (ddef @ DefDef(mods, _, _, _, _, _) <- templ.body if mods hasFlag MACRO) {
- val trace = scala.tools.nsc.util.trace when settings.Ymacrodebug.value
- val sym = namer.enterSyntheticSym(trace("macro def: ")(macroMethDef(ddef)))
- trace("added to "+namer.context.owner.enclClass+": ")(sym)
+ def computeMacroDefTypeFromMacroImpl(macroDdef: DefDef, macroDef: Symbol, macroImpl: Symbol): Type = {
+ // get return type from method type
+ def unwrapRet(tpe: Type): Type = {
+ def loop(tpe: Type) = tpe match {
+ case NullaryMethodType(ret) => ret
+ case mtpe @ MethodType(_, ret) => unwrapRet(ret)
+ case _ => tpe
+ }
+
+ tpe match {
+ case PolyType(_, tpe) => loop(tpe)
+ case _ => loop(tpe)
+ }
+ }
+ var metaType = unwrapRet(macroImpl.tpe)
+
+ // downgrade from metalevel-0 to metalevel-1
+ def inferRuntimeType(metaType: Type): Type = metaType match {
+ case TypeRef(pre, sym, args) if sym.name == tpnme.Expr && args.length == 1 =>
+ args.head
+ case _ =>
+ AnyClass.tpe
+ }
+ var runtimeType = inferRuntimeType(metaType)
+
+ // transform type parameters of a macro implementation into type parameters of a macro definition
+ runtimeType = runtimeType map {
+ case TypeRef(pre, sym, args) =>
+ // [Eugene] not sure which of these deSkolemizes are necessary
+ // sym.paramPos is unreliable (see another case below)
+ val tparams = macroImpl.typeParams map (_.deSkolemize)
+ val paramPos = tparams indexOf sym.deSkolemize
+ val sym1 = if (paramPos == -1) sym else {
+ val ann = macroDef.getAnnotation(MacroImplAnnotation)
+ ann match {
+ case Some(ann) =>
+ val TypeApply(_, implRefTargs) = ann.args(0)
+ val implRefTarg = implRefTargs(paramPos).tpe.typeSymbol
+ implRefTarg
+ case None =>
+ sym
+ }
+ }
+ TypeRef(pre, sym1, args)
+ case tpe =>
+ tpe
+ }
+
+ // as stated in the spec, before being matched to macroimpl, type and value parameters of macrodef
+ // undergo a special transformation, sigma, that adapts them to the different metalevel macroimpl lives in
+ // as a result, we need to reverse this transformation when inferring macrodef ret from macroimpl ret
+ def unsigma(tpe: Type): Type = {
+ // unfortunately, we cannot dereference ``paramss'', because we're in the middle of inferring a type for ``macroDef''
+// val defParamss = macroDef.paramss
+ val defParamss = macroDdef.vparamss map (_ map (_.symbol))
+ var implParamss = macroImpl.paramss
+ implParamss = transformTypeTagEvidenceParams(implParamss, (param, tparam) => None)
+
+ val implCtxParam = if (implParamss.length > 0 && implParamss(0).length > 0) implParamss(0)(0) else null
+ def implParamToDefParam(implParam: Symbol): Symbol = {
+ val indices = (implParamss drop 1 zipWithIndex) map { case (implParams, index) => (index, implParams indexOf implParam) } filter (_._2 != -1) headOption;
+ val defParam = indices flatMap {
+ case (plistIndex, pIndex) =>
+ if (defParamss.length <= plistIndex) None
+ else if (defParamss(plistIndex).length <= pIndex) None
+ else Some(defParamss(plistIndex)(pIndex))
+ }
+ defParam orNull
+ }
+
+ class UnsigmaTypeMap extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case TypeRef(pre, sym, args) =>
+ val pre1 = pre match {
+ case SingleType(SingleType(SingleType(NoPrefix, param), prefix), value) if param == implCtxParam && prefix == MacroContextPrefix && value == ExprValue =>
+ ThisType(macroDef.owner)
+ case SingleType(SingleType(NoPrefix, param), value) if implParamToDefParam(param) != null && value == ExprValue =>
+ val macroDefParam = implParamToDefParam(param)
+ SingleType(NoPrefix, macroDefParam)
+ case _ =>
+ pre
+ }
+ val args1 = args map mapOver
+ TypeRef(pre1, sym, args1)
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
+ new UnsigmaTypeMap() apply tpe
}
+ runtimeType = unsigma(runtimeType)
+
+ runtimeType
}
- lazy val mirror = new scala.reflect.runtime.Mirror {
- lazy val libraryClassLoader = {
- // todo. this is more or less okay, but not completely correct
- // see https://issues.scala-lang.org/browse/SI-5433 for more info
- val classpath = global.classPath.asURLs
- var loader: ClassLoader = ScalaClassLoader.fromURLs(classpath, self.getClass.getClassLoader)
-
- // an heuristic to detect REPL
- if (global.settings.exposeEmptyPackage.value) {
- import scala.tools.nsc.interpreter._
- val virtualDirectory = global.settings.outputDirs.getSingleOutput.get
- loader = new AbstractFileClassLoader(virtualDirectory, loader) {}
+ /** Primary mirror that is used to resolve and run macro implementations.
+ * Loads classes from -Xmacro-primary-classpath, or from -cp if the option is not specified.
+ */
+ private lazy val primaryMirror: Mirror = {
+ if (global.forMSIL)
+ throw new UnsupportedOperationException("Scala reflection not available on this platform")
+
+ val libraryClassLoader = {
+ if (settings.XmacroPrimaryClasspath.value != "") {
+ if (macroDebug) println("primary macro mirror: initializing from -Xmacro-primary-classpath: %s".format(settings.XmacroPrimaryClasspath.value))
+ val classpath = toURLs(settings.XmacroFallbackClasspath.value)
+ ScalaClassLoader.fromURLs(classpath, self.getClass.getClassLoader)
+ } else {
+ if (macroDebug) println("primary macro mirror: initializing from -cp: %s".format(global.classPath.asURLs))
+ val classpath = global.classPath.asURLs
+ var loader: ClassLoader = ScalaClassLoader.fromURLs(classpath, self.getClass.getClassLoader)
+
+ // [Eugene] a heuristic to detect REPL
+ if (global.settings.exposeEmptyPackage.value) {
+ import scala.tools.nsc.interpreter._
+ val virtualDirectory = global.settings.outputDirs.getSingleOutput.get
+ loader = new AbstractFileClassLoader(virtualDirectory, loader) {}
+ }
+
+ loader
}
+ }
+
+ new Mirror(libraryClassLoader) { override def toString = "<primary macro mirror>" }
+ }
- loader
+ /** Fallback mirror that is used to resolve and run macro implementations.
+ * Loads classes from -Xmacro-fallback-classpath aka "macro fallback classpath".
+ */
+ private lazy val fallbackMirror: Mirror = {
+ if (global.forMSIL)
+ throw new UnsupportedOperationException("Scala reflection not available on this platform")
+
+ val fallbackClassLoader = {
+ if (macroDebug) println("fallback macro mirror: initializing from -Xmacro-fallback-classpath: %s".format(settings.XmacroFallbackClasspath.value))
+ val classpath = toURLs(settings.XmacroFallbackClasspath.value)
+ ScalaClassLoader.fromURLs(classpath, self.getClass.getClassLoader)
}
- override def defaultReflectiveClassLoader() = libraryClassLoader
+ new Mirror(fallbackClassLoader) { override def toString = "<fallback macro mirror>" }
}
- /** Return optionally address of companion object and implementation method symbol
- * of given macro; or None if implementation classfile cannot be loaded or does
- * not contain the macro implementation.
+ /** Produces a function that can be used to invoke macro implementation for a given macro definition:
+ * 1) Looks up macro implementation symbol in this universe.
+ * 2) Loads its enclosing class from the primary mirror.
+ * 3) Loads the companion of that enclosing class from the primary mirror.
+ * 4) Resolves macro implementation within the loaded companion.
+ * 5) If 2-4 fails, repeats them for the fallback mirror.
+ *
+ * @return Some(runtime) if macro implementation can be loaded successfully from either of the mirrors,
+ * None otherwise.
*/
- def macroImpl(mac: Symbol): Option[(AnyRef, mirror.Symbol)] = {
- val debug = settings.Ymacrodebug.value
- val trace = scala.tools.nsc.util.trace when debug
- trace("looking for macro implementation: ")(mac.fullNameString)
-
- try {
- val mmeth = macroMeth(mac)
- trace("found implementation at: ")(mmeth.fullNameString)
-
- if (mmeth == NoSymbol) None
- else {
- trace("loading implementation class: ")(mmeth.owner.fullName)
- trace("classloader is: ")("%s of type %s".format(mirror.libraryClassLoader, mirror.libraryClassLoader.getClass))
+ private def macroRuntime(macroDef: Symbol): Option[List[Any] => Any] = {
+ macroTrace("looking for macro implementation: ")(macroDef)
+ macroTrace("macroDef is annotated with: ")(macroDef.annotations)
+
+ val ann = macroDef.getAnnotation(MacroImplAnnotation)
+ if (ann == None) {
+ macroTrace("@macroImpl annotation is missing (this means that macro definition failed to typecheck)")(macroDef)
+ return None
+ }
+
+ val macroImpl = ann.get.args(0).symbol
+ if (macroImpl == NoSymbol) {
+ macroTrace("@macroImpl annotation is malformed (this means that macro definition failed to typecheck)")(macroDef)
+ return None
+ }
+
+ if (macroDebug) println("resolved implementation %s at %s".format(macroImpl, macroImpl.pos))
+ if (macroImpl.isErroneous) {
+ macroTrace("macro implementation is erroneous (this means that either macro body or macro implementation signature failed to typecheck)")(macroDef)
+ return None
+ }
+
+ def loadMacroImpl(macroMirror: Mirror): Option[(Object, macroMirror.Symbol)] = {
+ try {
+ // this logic relies on the assumptions that were valid for the old macro prototype
+ // namely that macro implementations can only be defined in top-level classes and modules
+ // with the new prototype that materialized in a SIP, macros need to be statically accessible, which is different
+ // for example, a macro def could be defined in a trait that is implemented by an object
+ // there are some more clever cases when seemingly non-static method ends up being statically accessible
+ // however, the code below doesn't account for these guys, because it'd take a look of time to get it right
+ // for now I leave it as a todo and move along to more the important stuff
+
+ macroTrace("loading implementation class from %s: ".format(macroMirror))(macroImpl.owner.fullName)
+ macroTrace("classloader is: ")("%s of type %s".format(macroMirror.classLoader, if (macroMirror.classLoader != null) macroMirror.classLoader.getClass.toString else "primordial classloader"))
def inferClasspath(cl: ClassLoader) = cl match {
case cl: java.net.URLClassLoader => "[" + (cl.getURLs mkString ",") + "]"
+ case null => "[" + scala.tools.util.PathResolver.Environment.javaBootClassPath + "]"
case _ => "<unknown>"
}
- trace("classpath is: ")(inferClasspath(mirror.libraryClassLoader))
+ macroTrace("classpath is: ")(inferClasspath(macroMirror.classLoader))
- // @xeno.by: relies on the fact that macros can only be defined in static classes
+ // [Eugene] relies on the fact that macro implementations can only be defined in static classes
+ // [Martin to Eugene] There's similar logic buried in Symbol#flatname. Maybe we can refactor?
def classfile(sym: Symbol): String = {
def recur(sym: Symbol): String = sym match {
case sym if sym.owner.isPackageClass =>
@@ -146,145 +693,535 @@ trait Macros { self: Analyzer =>
else recur(sym.enclClass)
}
- // @xeno.by: this doesn't work for inner classes
- // neither does mmeth.owner.javaClassName, so I had to roll my own implementation
- //val receiverName = mmeth.owner.fullName
- val receiverName = classfile(mmeth.owner)
- val receiverClass: mirror.Symbol = mirror.symbolForName(receiverName)
+ // [Eugene] this doesn't work for inner classes
+ // neither does macroImpl.owner.javaClassName, so I had to roll my own implementation
+ //val receiverName = macroImpl.owner.fullName
+ val implClassName = classfile(macroImpl.owner)
+ val implClassSymbol: macroMirror.Symbol = macroMirror.symbolForName(implClassName)
- if (debug) {
- println("receiverClass is: " + receiverClass.fullNameString)
+ if (macroDebug) {
+ println("implClassSymbol is: " + implClassSymbol.fullNameString)
- val jreceiverClass = mirror.classToJava(receiverClass)
- val jreceiverSource = jreceiverClass.getProtectionDomain.getCodeSource
- println("jreceiverClass is %s from %s".format(jreceiverClass, jreceiverSource))
- println("jreceiverClassLoader is %s with classpath %s".format(jreceiverClass.getClassLoader, inferClasspath(jreceiverClass.getClassLoader)))
+ if (implClassSymbol != macroMirror.NoSymbol) {
+ val implClass = macroMirror.classToJava(implClassSymbol)
+ val implSource = implClass.getProtectionDomain.getCodeSource
+ println("implClass is %s from %s".format(implClass, implSource))
+ println("implClassLoader is %s with classpath %s".format(implClass.getClassLoader, inferClasspath(implClass.getClassLoader)))
+ }
}
- val receiverObj = receiverClass.companionModule
- trace("receiverObj is: ")(receiverObj.fullNameString)
+ val implObjSymbol = implClassSymbol.companionModule
+ macroTrace("implObjSymbol is: ")(implObjSymbol.fullNameString)
- if (receiverObj == mirror.NoSymbol) None
+ if (implObjSymbol == macroMirror.NoSymbol) None
else {
- // @xeno.by: yet another reflection method that doesn't work for inner classes
- //val receiver = mirror.companionInstance(receiverClass)
- val clazz = java.lang.Class.forName(receiverName, true, mirror.libraryClassLoader)
- val receiver = clazz getField "MODULE$" get null
-
- val rmeth = receiverObj.info.member(mirror.newTermName(mmeth.name.toString))
- if (debug) {
- println("rmeth is: " + rmeth.fullNameString)
- println("jrmeth is: " + mirror.methodToJava(rmeth))
+ // yet another reflection method that doesn't work for inner classes
+ //val receiver = macroMirror.companionInstance(receiverClass)
+ val implObj = try {
+ val implObjClass = java.lang.Class.forName(implClassName, true, macroMirror.classLoader)
+ implObjClass getField "MODULE$" get null
+ } catch {
+ case ex: NoSuchFieldException => macroTrace("exception when loading implObj: ")(ex); null
+ case ex: NoClassDefFoundError => macroTrace("exception when loading implObj: ")(ex); null
+ case ex: ClassNotFoundException => macroTrace("exception when loading implObj: ")(ex); null
}
- if (rmeth == mirror.NoSymbol) None
+ if (implObj == null) None
else {
- Some((receiver, rmeth))
+ val implMethSymbol = implObjSymbol.info.member(macroMirror.newTermName(macroImpl.name.toString))
+ if (macroDebug) {
+ println("implMethSymbol is: " + implMethSymbol.fullNameString)
+ println("jimplMethSymbol is: " + macroMirror.methodToJava(implMethSymbol))
+ }
+
+ if (implMethSymbol == macroMirror.NoSymbol) None
+ else {
+ if (macroDebug) println("successfully loaded macro impl as (%s, %s)".format(implObj, implMethSymbol))
+ Some((implObj, implMethSymbol))
+ }
}
}
+ } catch {
+ case ex: ClassNotFoundException =>
+ macroTrace("implementation class failed to load: ")(ex.toString)
+ None
}
- } catch {
- case ex: ClassNotFoundException =>
- trace("implementation class failed to load: ")(ex.toString)
- None
+ }
+
+ val primary = loadMacroImpl(primaryMirror)
+ primary match {
+ case Some((implObj, implMethSymbol)) =>
+ def runtime(args: List[Any]) = primaryMirror.invoke(implObj, implMethSymbol)(args: _*).asInstanceOf[Any]
+ Some(runtime)
+ case None =>
+ if (settings.XmacroFallbackClasspath.value != "") {
+ if (macroDebug) println("trying to load macro implementation from the fallback mirror: %s".format(settings.XmacroFallbackClasspath.value))
+ val fallback = loadMacroImpl(fallbackMirror)
+ fallback match {
+ case Some((implObj, implMethSymbol)) =>
+ def runtime(args: List[Any]) = fallbackMirror.invoke(implObj, implMethSymbol)(args: _*).asInstanceOf[Any]
+ Some(runtime)
+ case None =>
+ None
+ }
+ } else {
+ None
+ }
}
}
- /** Return result of macro expansion.
- * Or, if that fails, and the macro overrides a method return
- * tree that calls this method instead of the macro.
+ /** Should become private again once we're done with migrating typetag generation from implicits */
+ def macroContext(typer: Typer, prefixTree: Tree, expandeeTree: Tree): MacroContext { val mirror: global.type } =
+ new {
+ val mirror: global.type = global
+ val callsiteTyper: mirror.analyzer.Typer = typer.asInstanceOf[global.analyzer.Typer]
+ // todo. infer precise typetag for this Expr, namely the PrefixType member of the Context refinement
+ val prefix = Expr(prefixTree)(TypeTag.Nothing)
+ val expandee = expandeeTree
+ } with MacroContext {
+ override def toString = "MacroContext(%s@%s +%d)".format(expandee.symbol.name, expandee.pos, openMacros.length - 1 /* exclude myself */)
+ }
+
+ /** Calculate the arguments to pass to a macro implementation when expanding the provided tree.
+ *
+ * This includes inferring the exact type and instance of the macro context to pass, and also
+ * allowing for missing parameter sections in macro implementation (see ``macroImplParamsss'' for more info).
+ *
+ * @return list of runtime objects to pass to the implementation obtained by ``macroRuntime''
*/
- def macroExpand(tree: Tree, typer: Typer): Option[Any] = {
- val trace = scala.tools.nsc.util.trace when settings.Ymacrodebug.value
- trace("macroExpand: ")(tree)
-
- val macroDef = tree.symbol
- macroImpl(macroDef) match {
- case Some((receiver, rmeth)) =>
- val argss = List(global) :: macroArgs(tree)
- val paramss = macroMeth(macroDef).paramss
- trace("paramss: ")(paramss)
- val rawArgss = for ((as, ps) <- argss zip paramss) yield {
- if (isVarArgsList(ps)) as.take(ps.length - 1) :+ as.drop(ps.length - 1)
- else as
- }
- val rawArgs: Seq[Any] = rawArgss.flatten
- trace("rawArgs: ")(rawArgs)
- val savedInfolevel = nodePrinters.infolevel
+ private def macroArgs(typer: Typer, expandee: Tree): Option[List[Any]] = {
+ var prefixTree: Tree = EmptyTree
+ var typeArgs = List[Tree]()
+ val exprArgs = new ListBuffer[List[Expr[_]]]
+ def collectMacroArgs(tree: Tree): Unit = tree match {
+ case Apply(fn, args) =>
+ // todo. infer precise typetag for this Expr, namely the declared type of the corresponding macro impl argument
+ exprArgs.prepend(args map (Expr(_)(TypeTag.Nothing)))
+ collectMacroArgs(fn)
+ case TypeApply(fn, args) =>
+ typeArgs = args
+ collectMacroArgs(fn)
+ case Select(qual, name) =>
+ prefixTree = qual
+ case _ =>
+ }
+ collectMacroArgs(expandee)
+ val context = macroContext(typer, prefixTree, expandee)
+ var argss: List[List[Any]] = List(context) :: exprArgs.toList
+ macroTrace("argss: ")(argss)
+
+ val macroDef = expandee.symbol
+ val ann = macroDef.getAnnotation(MacroImplAnnotation).getOrElse(throw new Error("assertion failed. %s: %s".format(macroDef, macroDef.annotations)))
+ val macroImpl = ann.args(0).symbol
+ var paramss = macroImpl.paramss
+ val tparams = macroImpl.typeParams
+ macroTrace("paramss: ")(paramss)
+
+ // we need to take care of all possible combos of nullary/empty-paramlist macro defs vs nullary/empty-arglist invocations
+ // nullary def + nullary invocation => paramss and argss match, everything is okay
+ // nullary def + empty-arglist invocation => illegal Scala code, impossible, everything is okay
+ // empty-paramlist def + nullary invocation => uh-oh, we need to append a List() to argss
+ // empty-paramlist def + empty-arglist invocation => paramss and argss match, everything is okay
+ // that's almost it, but we need to account for the fact that paramss might have context bounds that mask the empty last paramlist
+ val paramss_without_evidences = transformTypeTagEvidenceParams(paramss, (param, tparam) => None)
+ val isEmptyParamlistDef = paramss_without_evidences.length != 0 && paramss_without_evidences.last.isEmpty
+ val isEmptyArglistInvocation = argss.length != 0 && argss.last.isEmpty
+ if (isEmptyParamlistDef && !isEmptyArglistInvocation) {
+ if (macroDebug) println("isEmptyParamlistDef && !isEmptyArglistInvocation: appending a List() to argss")
+ argss = argss :+ Nil
+ }
+
+ // nb! check partial application against paramss without evidences
+ val numParamLists = paramss_without_evidences.length
+ val numArgLists = argss.length
+ if (numParamLists != numArgLists) {
+ typer.context.error(expandee.pos, "macros cannot be partially applied")
+ return None
+ }
+
+ // if paramss have typetag context bounds, add an arglist to argss if necessary and instantiate the corresponding evidences
+ // consider the following example:
+ //
+ // class D[T] {
+ // class C[U] {
+ // def foo[V] = macro Impls.foo[T, U, V]
+ // }
+ // }
+ //
+ // val outer1 = new D[Int]
+ // val outer2 = new outer1.C[String]
+ // outer2.foo[Boolean]
+ //
+ // then T and U need to be inferred from the lexical scope of the call using ``asSeenFrom''
+ // whereas V won't be resolved by asSeenFrom and need to be loaded directly from ``expandee'' which needs to contain a TypeApply node
+ // also, macro implementation reference may contain a regular type as a type argument, then we pass it verbatim
+ paramss = transformTypeTagEvidenceParams(paramss, (param, tparam) => Some(tparam))
+ if (paramss.lastOption map (params => !params.isEmpty && params.forall(_.isType)) getOrElse false) argss = argss :+ Nil
+ val evidences = paramss.last takeWhile (_.isType) map (tparam => {
+ val TypeApply(_, implRefTargs) = ann.args(0)
+ var implRefTarg = implRefTargs(tparam.paramPos).tpe.typeSymbol
+ val tpe = if (implRefTarg.isTypeParameterOrSkolem) {
+ if (implRefTarg.owner == macroDef) {
+ // [Eugene] doesn't work when macro def is compiled separately from its usages
+ // then implRefTarg is not a skolem and isn't equal to any of macroDef.typeParams
+// val paramPos = implRefTarg.deSkolemize.paramPos
+ val paramPos = macroDef.typeParams.indexWhere(_.name == implRefTarg.name)
+ typeArgs(paramPos).tpe
+ } else
+ implRefTarg.tpe.asSeenFrom(
+ if (prefixTree == EmptyTree) macroDef.owner.tpe else prefixTree.tpe,
+ macroDef.owner)
+ } else
+ implRefTarg.tpe
+ if (macroDebug) println("resolved tparam %s as %s".format(tparam, tpe))
+ tpe
+ }) map (tpe => {
+ val ttag = TypeTag(tpe)
+ if (ttag.isConcrete) ttag.toConcrete else ttag
+ })
+ argss = argss.dropRight(1) :+ (evidences ++ argss.last)
+
+ assert(argss.length == paramss.length, "argss: %s, paramss: %s".format(argss, paramss))
+ val rawArgss = for ((as, ps) <- argss zip paramss) yield {
+ if (isVarArgsList(ps)) as.take(ps.length - 1) :+ as.drop(ps.length - 1)
+ else as
+ }
+ val rawArgs = rawArgss.flatten
+ macroTrace("rawArgs: ")(rawArgs)
+ Some(rawArgs)
+ }
+
+ /** Keeps track of macros in-flight.
+ * See more informations in comments to ``openMacros'' in ``scala.reflect.makro.Context''.
+ */
+ var openMacros = List[MacroContext]()
+
+ /** Performs macro expansion:
+ * 1) Checks whether the expansion needs to be delayed (see ``mustDelayMacroExpansion'')
+ * 2) Loads macro implementation using ``macroMirror''
+ * 3) Synthesizes invocation arguments for the macro implementation
+ * 4) Checks that the result is a tree bound to this universe
+ * 5) Typechecks the result against the return type of the macro definition
+ *
+ * If -Ymacro-debug is enabled, you will get detailed log of how exactly this function
+ * performs class loading and method resolution in order to load the macro implementation.
+ * The log will also include other non-trivial steps of macro expansion.
+ *
+ * If -Ymacro-copypaste is enabled along with -Ymacro-debug, you will get macro expansions
+ * logged in the form that can be copy/pasted verbatim into REPL (useful for debugging!).
+ *
+ * @return
+ * the expansion result if the expansion has been successful,
+ * the fallback method invocation if the expansion has been unsuccessful, but there is a fallback,
+ * the expandee unchanged if the expansion has been delayed,
+ * the expandee fully expanded if the expansion has been delayed before and has been expanded now,
+ * the expandee with an error marker set if the expansion has been cancelled due malformed arguments or implementation
+ * the expandee with an error marker set if there has been an error
+ */
+ def macroExpand(typer: Typer, expandee: Tree, pt: Type): Tree =
+ macroExpand1(typer, expandee) match {
+ case Success(expanded) =>
try {
- // @xeno.by: InfoLevel.Verbose examines and prints out infos of symbols
- // by the means of this'es these symbols can climb up the lexical scope
- // when these symbols will be examined by a node printer
- // they will enumerate and analyze their children (ask for infos and tpes)
- // if one of those children involves macro expansion, things might get nasty
- // that's why I'm temporarily turning this behavior off
- nodePrinters.infolevel = nodePrinters.InfoLevel.Quiet
- val expanded = mirror.invoke(receiver, rmeth)(rawArgs: _*)
- expanded match {
- case expanded: Tree =>
- val expectedTpe = tree.tpe
- val typed = typer.typed(expanded, EXPRmode, expectedTpe)
- Some(typed)
- case expanded if expanded.isInstanceOf[Tree] =>
- typer.context.unit.error(tree.pos, "macro must return a compiler-specific tree; returned value is Tree, but it doesn't belong to this compiler's universe")
- None
- case expanded =>
- typer.context.unit.error(tree.pos, "macro must return a compiler-specific tree; returned value is of class: " + expanded.getClass)
- None
+ var expectedTpe = expandee.tpe
+
+ // [Eugene] weird situation. what's the conventional way to deal with it?
+ val isNullaryInvocation = expandee match {
+ case TypeApply(Select(_, _), _) => true
+ case Select(_, _) => true
+ case _ => false
}
- } catch {
- case ex =>
- val realex = ReflectionUtils.unwrapThrowable(ex)
- val msg = if (settings.Ymacrodebug.value) {
- val stacktrace = new java.io.StringWriter()
- realex.printStackTrace(new java.io.PrintWriter(stacktrace))
- System.getProperty("line.separator") + stacktrace
- } else {
- realex.getMessage
- }
- typer.context.unit.error(tree.pos, "exception during macro expansion: " + msg)
- None
+ if (isNullaryInvocation) expectedTpe match {
+ case MethodType(Nil, restpe) =>
+ macroTrace("nullary invocation of a method with an empty parameter list. unwrapping expectedTpe from " + expectedTpe + " to:")(restpe)
+ expectedTpe = restpe
+ case _ => ;
+ }
+
+ var typechecked = typer.context.withImplicitsEnabled(typer.typed(expanded, EXPRmode, expectedTpe))
+ if (macroDebug) {
+ println("typechecked1:")
+ println(typechecked)
+ println(showRaw(typechecked))
+ }
+
+ typechecked = typer.context.withImplicitsEnabled(typer.typed(typechecked, EXPRmode, pt))
+ if (macroDebug) {
+ println("typechecked2:")
+ println(typechecked)
+ println(showRaw(typechecked))
+ }
+
+ typechecked
} finally {
- nodePrinters.infolevel = savedInfolevel
+ openMacros = openMacros.tail
}
- case None =>
- def notFound() = {
- typer.context.unit.error(tree.pos, "macro implementation not found: " + macroDef.name)
- None
- }
- def fallBackToOverridden(tree: Tree): Option[Tree] = {
- tree match {
- case Select(qual, name) if (macroDef.isMacro) =>
- macroDef.allOverriddenSymbols match {
- case first :: _ =>
- Some(Select(qual, name) setPos tree.pos setSymbol first)
+ case Fallback(fallback) =>
+ typer.context.withImplicitsEnabled(typer.typed(fallback, EXPRmode, pt))
+ case Other(result) =>
+ result
+ }
+
+ private sealed abstract class MacroExpansionResult extends Product with Serializable
+ private case class Success(expanded: Tree) extends MacroExpansionResult
+ private case class Fallback(fallback: Tree) extends MacroExpansionResult
+ private case class Other(result: Tree) extends MacroExpansionResult
+ private def Delay(expandee: Tree) = Other(expandee)
+ private def Skip(expanded: Tree) = Other(expanded)
+ private def Cancel(expandee: Tree) = Other(expandee)
+ private def Failure(expandee: Tree) = Other(expandee)
+ private def fail(typer: Typer, expandee: Tree, msg: String = null) = {
+ if (macroDebug || macroCopypaste) {
+ var msg1 = if (msg contains "exception during macro expansion") msg.split(EOL).drop(1).headOption.getOrElse("?") else msg
+ if (macroDebug) msg1 = msg
+ println("macro expansion has failed: %s".format(msg1))
+ }
+ val pos = if (expandee.pos != NoPosition) expandee.pos else openMacros.find(c => c.expandee.pos != NoPosition).map(_.expandee.pos).getOrElse(NoPosition)
+ if (msg != null) typer.context.error(pos, msg)
+ typer.infer.setError(expandee)
+ Failure(expandee)
+ }
+
+ /** Does the same as ``macroExpand'', but without typechecking the expansion
+ * Meant for internal use within the macro infrastructure, don't use it elsewhere.
+ */
+ private def macroExpand1(typer: Typer, expandee: Tree): MacroExpansionResult = {
+ // if a macro implementation is incompatible or any of the arguments are erroneous
+ // there is no sense to expand the macro itself => it will only make matters worse
+ if (expandee.symbol.isErroneous || (expandee exists (_.isErroneous))) {
+ val reason = if (expandee.symbol.isErroneous) "incompatible macro implementation" else "erroneous arguments"
+ macroTrace("cancelled macro expansion because of %s: ".format(reason))(expandee)
+ return Cancel(typer.infer.setError(expandee))
+ }
+
+ if (!isDelayed(expandee)) {
+ if (macroDebug || macroCopypaste) println("typechecking macro expansion %s at %s".format(expandee, expandee.pos))
+
+ val undetparams = calculateUndetparams(expandee)
+ if (undetparams.size != 0) {
+ macroTrace("macro expansion is delayed: ")(expandee)
+ delayed += expandee -> (typer.context, undetparams)
+ Delay(expandee)
+ } else {
+ val macroDef = expandee.symbol
+ macroRuntime(macroDef) match {
+ case Some(runtime) =>
+ val savedInfolevel = nodePrinters.infolevel
+ try {
+ // InfoLevel.Verbose examines and prints out infos of symbols
+ // by the means of this'es these symbols can climb up the lexical scope
+ // when these symbols will be examined by a node printer
+ // they will enumerate and analyze their children (ask for infos and tpes)
+ // if one of those children involves macro expansion, things might get nasty
+ // that's why I'm temporarily turning this behavior off
+ nodePrinters.infolevel = nodePrinters.InfoLevel.Quiet
+ val args = macroArgs(typer, expandee)
+ args match {
+ case Some(args) =>
+ // adding stuff to openMacros is easy, but removing it is a nightmare
+ // it needs to be sprinkled over several different code locations
+ val (context: MacroContext) :: _ = args
+ openMacros = context :: openMacros
+ val expanded: MacroExpansionResult = try {
+ val prevNumErrors = reporter.ERROR.count
+ val expanded = runtime(args)
+ val currNumErrors = reporter.ERROR.count
+ if (currNumErrors != prevNumErrors) {
+ fail(typer, expandee) // errors have been reported by the macro itself
+ } else {
+ expanded match {
+ case expanded: Expr[_] =>
+ if (macroDebug || macroCopypaste) {
+ if (macroDebug) println("original:")
+ println(expanded.tree)
+ println(showRaw(expanded.tree))
+ }
+
+ freeTerms(expanded.tree) foreach (fte => typer.context.error(expandee.pos,
+ ("macro expansion contains free term variable %s %s. "+
+ "have you forgot to use eval when splicing this variable into a reifee? " +
+ "if you have troubles tracking free term variables, consider using -Xlog-free-terms").format(fte.name, fte.origin)))
+ freeTypes(expanded.tree) foreach (fty => typer.context.error(expandee.pos,
+ ("macro expansion contains free type variable %s %s. "+
+ "have you forgot to use c.TypeTag annotation for this type parameter? " +
+ "if you have troubles tracking free type variables, consider using -Xlog-free-types").format(fty.name, fty.origin)))
+
+ val currNumErrors = reporter.ERROR.count
+ if (currNumErrors != prevNumErrors) {
+ fail(typer, expandee)
+ } else {
+ // inherit the position from the first position-ful expandee in macro callstack
+ // this is essential for sane error messages
+ var tree = expanded.tree
+ var position = openMacros.find(c => c.expandee.pos != NoPosition).map(_.expandee.pos).getOrElse(NoPosition)
+ tree = atPos(position.focus)(tree)
+
+ // now macro expansion gets typechecked against the macro definition return type
+ // however, this happens in macroExpand, not here in macroExpand1
+ Success(tree)
+ }
+ case expanded if expanded.isInstanceOf[Expr[_]] =>
+ val msg = "macro must return a compiler-specific expr; returned value is Expr, but it doesn't belong to this compiler's universe"
+ fail(typer, expandee, msg)
+ case expanded =>
+ val msg = "macro must return a compiler-specific expr; returned value is of class: %s".format(expanded.getClass)
+ fail(typer, expandee, msg)
+ }
+ }
+ } catch {
+ case ex: Throwable =>
+ openMacros = openMacros.tail
+ throw ex
+ }
+ if (!expanded.isInstanceOf[Success]) openMacros = openMacros.tail
+ expanded
+ case None =>
+ fail(typer, expandee) // error has been reported by macroArgs
+ }
+ } catch {
+ case ex =>
+ // [Eugene] any ideas about how to improve this one?
+ val realex = ReflectionUtils.unwrapThrowable(ex)
+ realex match {
+ case realex: reflect.makro.runtime.AbortMacroException =>
+ if (macroDebug || macroCopypaste) println("macro expansion has failed: %s".format(realex.msg))
+ fail(typer, expandee) // error has been reported by abort
+ case _ =>
+ val message = {
+ try {
+ // the most reliable way of obtaining currently executing method
+ // http://stackoverflow.com/questions/442747/getting-the-name-of-the-current-executing-method
+ val currentMethodName = new Object(){}.getClass().getEnclosingMethod().getName
+ val relevancyThreshold = realex.getStackTrace().indexWhere(este => este.getMethodName == currentMethodName)
+ if (relevancyThreshold == -1) None
+ else {
+ var relevantElements = realex.getStackTrace().take(relevancyThreshold + 1)
+ var framesTillReflectiveInvocationOfMacroImpl = relevantElements.reverse.indexWhere(_.isNativeMethod) + 1
+ relevantElements = relevantElements dropRight framesTillReflectiveInvocationOfMacroImpl
+
+ realex.setStackTrace(relevantElements)
+ val message = new java.io.StringWriter()
+ realex.printStackTrace(new java.io.PrintWriter(message))
+ Some(EOL + message)
+ }
+ } catch {
+ // if the magic above goes boom, just fall back to uninformative, but better than nothing, getMessage
+ case ex: Throwable =>
+ None
+ }
+ } getOrElse realex.getMessage
+ fail(typer, expandee, "exception during macro expansion: " + message)
+ }
+ } finally {
+ nodePrinters.infolevel = savedInfolevel
+ }
+ case None =>
+ def notFound() = {
+ typer.context.error(expandee.pos, "macro implementation not found: " + macroDef.name + " " +
+ "(the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)\n" +
+ "if you do need to define macro implementations along with the rest of your program, consider two-phase compilation with -Xmacro-fallback-classpath " +
+ "in the second phase pointing to the output of the first phase")
+ None
+ }
+ def fallBackToOverridden(tree: Tree): Option[Tree] = {
+ tree match {
+ case Select(qual, name) if (macroDef.isTermMacro) =>
+ macroDef.allOverriddenSymbols match {
+ case first :: _ =>
+ Some(Select(qual, name) setPos tree.pos setSymbol first)
+ case _ =>
+ macroTrace("macro is not overridden: ")(tree)
+ notFound()
+ }
+ case Apply(fn, args) =>
+ fallBackToOverridden(fn) match {
+ case Some(fn1) => Some(Apply(fn1, args) setPos tree.pos)
+ case _ => None
+ }
+ case TypeApply(fn, args) =>
+ fallBackToOverridden(fn) match {
+ case Some(fn1) => Some(TypeApply(fn1, args) setPos tree.pos)
+ case _ => None
+ }
case _ =>
- trace("macro is not overridden: ")(tree)
+ macroTrace("unexpected tree in fallback: ")(tree)
notFound()
}
- case Apply(fn, args) =>
- fallBackToOverridden(fn) match {
- case Some(fn1) => Some(Apply(fn1, args) setPos tree.pos)
- case _ => None
- }
- case TypeApply(fn, args) =>
- fallBackToOverridden(fn) match {
- case Some(fn1) => Some(TypeApply(fn1, args) setPos tree.pos)
- case _ => None
- }
- case _ =>
- trace("unexpected tree in fallback: ")(tree)
- notFound()
- }
- }
- fallBackToOverridden(tree) match {
- case Some(tree1) =>
- trace("falling back to ")(tree1)
- currentRun.macroExpansionFailed = true
- Some(tree1)
- case None =>
- None
+ }
+ fallBackToOverridden(expandee) match {
+ case Some(tree1) =>
+ macroTrace("falling back to ")(tree1)
+ currentRun.macroExpansionFailed = true
+ Fallback(tree1)
+ case None =>
+ fail(typer, expandee)
+ }
}
+ }
+ } else {
+ val undetparams = calculateUndetparams(expandee)
+ if (undetparams.size != 0)
+ Delay(expandee)
+ else
+ Skip(macroExpandAll(typer, expandee))
}
}
+
+ /** Without any restrictions on macro expansion, macro applications will expand at will,
+ * and when type inference is involved, expansions will end up using yet uninferred type params.
+ *
+ * For some macros this might be ok (thanks to TreeTypeSubstituter that replaces
+ * the occurrences of undetparams with their inferred values), but in general case this won't work.
+ * E.g. for reification simple substitution is not enough - we actually need to re-reify inferred types.
+ *
+ * Luckily, there exists a very simple way to fix the problem: delay macro expansion until everything is inferred.
+ * Here are the exact rules. Macro application gets delayed if any of its subtrees contain:
+ * 1) type vars (tpe.isInstanceOf[TypeVar]) // [Eugene] this check is disabled right now, because TypeVars seem to be created from undetparams anyways
+ * 2) undetparams (sym.isTypeParameter && !sym.isSkolem)
+ */
+ var hasPendingMacroExpansions = false
+ private val delayed = perRunCaches.newWeakMap[Tree, (Context, collection.mutable.Set[Int])]
+ private def isDelayed(expandee: Tree) = delayed contains expandee
+ private def calculateUndetparams(expandee: Tree): collection.mutable.Set[Int] =
+ delayed.get(expandee).map(_._2).getOrElse {
+ val calculated = collection.mutable.Set[Int]()
+ expandee foreach (sub => {
+ def traverse(sym: Symbol) = if (sym != null && (undetparams contains sym.id)) calculated += sym.id
+ if (sub.symbol != null) traverse(sub.symbol)
+ if (sub.tpe != null) sub.tpe foreach (sub => traverse(sub.typeSymbol))
+ })
+ calculated
+ }
+ private val undetparams = perRunCaches.newSet[Int]
+ def notifyUndetparamsAdded(newUndets: List[Symbol]): Unit = undetparams ++= newUndets map (_.id)
+ def notifyUndetparamsInferred(undetNoMore: List[Symbol], inferreds: List[Type]): Unit = {
+ undetparams --= undetNoMore map (_.id)
+ if (!delayed.isEmpty)
+ delayed.toList foreach {
+ case (expandee, (_, undetparams)) if !undetparams.isEmpty =>
+ undetparams --= undetNoMore map (_.id)
+ if (undetparams.isEmpty) {
+ hasPendingMacroExpansions = true
+ macroTrace("macro expansion is pending: ")(expandee)
+ }
+ case _ =>
+ // do nothing
+ }
+ }
+
+ /** Performs macro expansion on all subtrees of a given tree.
+ * Innermost macros are expanded first, outermost macros are expanded last.
+ * See the documentation for ``macroExpand'' for more information.
+ */
+ def macroExpandAll(typer: Typer, expandee: Tree): Tree =
+ new Transformer {
+ override def transform(tree: Tree) = super.transform(tree match {
+ // todo. expansion should work from the inside out
+ case wannabe if (delayed contains wannabe) && calculateUndetparams(wannabe).isEmpty =>
+ val (context, _) = delayed(wannabe)
+ delayed -= wannabe
+ macroExpand(newTyper(context), wannabe, WildcardType)
+ case _ =>
+ tree
+ })
+ }.transform(expandee)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
index b57f139074..e1c12adbcc 100644
--- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
@@ -28,6 +28,7 @@ trait MethodSynthesis {
else DefDef(sym, body)
def applyTypeInternal(manifests: List[M[_]]): Type = {
+ // [Eugene to Paul] needs review!!
val symbols = manifests map manifestToSymbol
val container :: args = symbols
val tparams = container.typeConstructor.typeParams
@@ -37,7 +38,7 @@ trait MethodSynthesis {
require(container.owner.isPackageClass, "Container must be a top-level class in a package: " + container)
require(tparams.size == args.size, "Arguments must match type constructor arity: " + tparams + ", " + args)
- typeRef(container.typeConstructor.prefix, container, args map (_.tpe))
+ appliedType(container, args map (_.tpe): _*)
}
def companionType[T](implicit m: M[T]) =
@@ -58,14 +59,32 @@ trait MethodSynthesis {
def newMethodType[F](owner: Symbol)(implicit m: Manifest[F]): Type = {
val fnSymbol = manifestToSymbol(m)
- assert(fnSymbol isSubClass FunctionClass(m.typeArguments.size - 1), (owner, m))
- val symbols = m.typeArguments map (m => manifestToSymbol(m))
- val formals = symbols.init map (_.typeConstructor)
+ assert(fnSymbol isSubClass FunctionClass(m.tpe.typeArguments.size - 1), (owner, m))
+ // [Eugene to Paul] needs review!!
+ // val symbols = m.typeArguments map (m => manifestToSymbol(m))
+ // val formals = symbols.init map (_.typeConstructor)
+ val formals = manifestToType(m).typeArguments
val params = owner newSyntheticValueParams formals
-
- MethodType(params, symbols.last.typeConstructor)
+ MethodType(params, formals.last)
}
- }
+
+ /** The annotations amongst those found on the original symbol which
+ * should be propagated to this kind of accessor.
+ */
+ def deriveAnnotations(initial: List[AnnotationInfo], category: Symbol, keepClean: Boolean): List[AnnotationInfo] = {
+ initial filter { ann =>
+ // There are no meta-annotation arguments attached to `ann`
+ if (ann.metaAnnotations.isEmpty) {
+ // A meta-annotation matching `annotKind` exists on `ann`'s definition.
+ (ann.defaultTargets contains category) ||
+ // `ann`'s definition has no meta-annotations, and `keepClean` is true.
+ (ann.defaultTargets.isEmpty && keepClean)
+ }
+ // There are meta-annotation arguments, and one of them matches `annotKind`
+ else ann.metaAnnotations exists (_ matches category)
+ }
+ }
+ }
import synthesisUtil._
class ClassMethodSynthesis(val clazz: Symbol, localTyper: Typer) {
@@ -96,8 +115,7 @@ trait MethodSynthesis {
finishMethod(m setInfoAndEnter infoFn(m), f)
}
private def cloneInternal(original: Symbol, f: Symbol => Tree, name: Name): Tree = {
- val m = original.cloneSymbol(clazz, newMethodFlags(original)) setPos clazz.pos.focus
- m.name = name
+ val m = original.cloneSymbol(clazz, newMethodFlags(original), name) setPos clazz.pos.focus
finishMethod(clazz.info.decls enter m, f)
}
@@ -156,28 +174,23 @@ trait MethodSynthesis {
/** There are two key methods in here.
*
- * 1) enterGetterSetter is called from Namer with a ValDef which
- * may need accessors. Some setup is performed. In general this
- * creates symbols and enters them into the scope of the owner.
+ * 1) Enter methods such as enterGetterSetterare called
+ * from Namer with a tree which may generate further trees such as accessors or
+ * implicit wrappers. Some setup is performed. In general this creates symbols
+ * and enters them into the scope of the owner.
*
- * 2) finishGetterSetter is called from Typer when a Template is typed.
+ * 2) addDerivedTrees is called from Typer when a Template is typed.
* It completes the job, returning a list of trees with their symbols
- * set to those created in enterGetterSetter. Those trees then become
+ * set to those created in the enter methods. Those trees then become
* part of the typed template.
*/
trait MethodSynth {
self: Namer =>
import NamerErrorGen._
-
- /** TODO - synthesize method.
- */
- def enterImplicitClass(tree: ClassDef) {
- /** e.g.
- val ClassDef(mods, name, tparams, impl) = tree
- val converter = ImplicitClassConverter(tree).createAndEnterSymbol()
- ...
- */
+
+ def enterImplicitWrapper(tree: ClassDef) {
+ ImplicitClassWrapper(tree).createAndEnterSymbol()
}
def enterGetterSetter(tree: ValDef) {
@@ -204,7 +217,8 @@ trait MethodSynthesis {
enterBeans(tree)
}
- def finishGetterSetter(typer: Typer, stat: Tree): List[Tree] = stat match {
+
+ def addDerivedTrees(typer: Typer, stat: Tree): List[Tree] = stat match {
case vd @ ValDef(mods, name, tpt, rhs) if !noFinishGetterSetter(vd) && !vd.symbol.isLazy =>
// If we don't save the annotations, they seem to wander off.
val annotations = stat.symbol.initialize.annotations
@@ -212,9 +226,19 @@ trait MethodSynthesis {
map (acc => atPos(vd.pos.focus)(acc derive annotations))
filterNot (_ eq EmptyTree)
)
+ case cd @ ClassDef(mods, _, _, _) if mods.isImplicit =>
+ val annotations = stat.symbol.initialize.annotations
+ // TODO: need to shuffle annotations between wrapper and class.
+ val wrapper = ImplicitClassWrapper(cd)
+ val meth = wrapper.derivedSym
+ val mdef = context.unit.synthetics(meth)
+ context.unit.synthetics -= meth
+ meth setAnnotations deriveAnnotations(annotations, MethodTargetClass, false)
+ cd.symbol setAnnotations deriveAnnotations(annotations, ClassTargetClass, true)
+ List(cd, mdef)
case _ =>
List(stat)
- }
+ }
def standardAccessors(vd: ValDef): List[DerivedFromValDef] = (
if (vd.mods.isMutable && !vd.mods.isLazy) List(Getter(vd), Setter(vd))
@@ -235,35 +259,59 @@ trait MethodSynthesis {
field ::: standardAccessors(vd) ::: beanAccessors(vd)
}
+ /** This trait assembles what's needed for synthesizing derived methods.
+ * Important: Typically, instances of this trait are created TWICE for each derived
+ * symbol; once form Namers in an enter method, and once from Typers in addDerivedTrees.
+ * So it's important that creating an instance of Derived does not have a side effect,
+ * or if it has a side effect, control that it is done only once.
+ */
trait Derived {
- /** The tree from which we are deriving a synthetic member. */
+
+ /** The tree from which we are deriving a synthetic member. Typically, that's
+ * given as an argument of the instance. */
def tree: Tree
+
+ /** The name of the method */
def name: TermName
+
+ /** The flags that are retained from the original symbol */
+
def flagsMask: Long
+
+ /** The flags that the derived symbol has in addition to those retained from
+ * the original symbol*/
def flagsExtra: Long
-
- /** The tree, symbol, and type completer for the synthetic member. */
+
+ /** type completer for the synthetic member.
+ */
def completer(sym: Symbol): Type
+
+ /** The derived symbol. It is assumed that this symbol already exists and has been
+ * entered in the parent scope when derivedSym is called */
def derivedSym: Symbol
+
+ /** The definition tree of the derived symbol. */
def derivedTree: Tree
}
-
+
trait DerivedFromMemberDef extends Derived {
def tree: MemberDef
-
+ def enclClass: Symbol
+
// Final methods to make the rest easier to reason about.
final def mods = tree.mods
final def basisSym = tree.symbol
- final def enclClass = basisSym.enclClass
final def derivedFlags: Long = basisSym.flags & flagsMask | flagsExtra
}
-
+
trait DerivedFromClassDef extends DerivedFromMemberDef {
def tree: ClassDef
+ final def enclClass = basisSym.owner.enclClass
}
trait DerivedFromValDef extends DerivedFromMemberDef {
def tree: ValDef
+ final def enclClass = basisSym.enclClass
/** Which meta-annotation is associated with this kind of entity.
* Presently one of: field, getter, setter, beanGetter, beanSetter, param.
@@ -287,31 +335,15 @@ trait MethodSynthesis {
enterInScope(sym)
sym setInfo completer(sym)
}
- /** The annotations amongst those found on the original symbol which
- * should be propagated to this kind of accessor.
- */
- private def deriveAnnotations(initial: List[AnnotationInfo]): List[AnnotationInfo] = {
- initial filter { ann =>
- // There are no meta-annotation arguments attached to `ann`
- if (ann.metaAnnotations.isEmpty) {
- // A meta-annotation matching `annotKind` exists on `ann`'s definition.
- (ann.defaultTargets contains category) ||
- // `ann`'s definition has no meta-annotations, and `keepClean` is true.
- (ann.defaultTargets.isEmpty && keepClean)
- }
- // There are meta-annotation arguments, and one of them matches `annotKind`
- else ann.metaAnnotations exists (_ matches category)
- }
- }
private def logDerived(result: Tree): Tree = {
- debuglog("[+derived] " + ojoin(mods.defaultFlagString, basisSym.accurateKindString, basisSym.getterName.decode)
+ debuglog("[+derived] " + ojoin(mods.flagString, basisSym.accurateKindString, basisSym.getterName.decode)
+ " (" + derivedSym + ")\n " + result)
result
}
final def derive(initial: List[AnnotationInfo]): Tree = {
validate()
- derivedSym setAnnotations deriveAnnotations(initial)
+ derivedSym setAnnotations deriveAnnotations(initial, category, keepClean)
logDerived(derivedTree)
}
}
@@ -335,15 +367,21 @@ trait MethodSynthesis {
/** A synthetic method which performs the implicit conversion implied by
* the declaration of an implicit class. Yet to be written.
*/
- case class ImplicitClassConverter(tree: ClassDef) extends DerivedFromClassDef {
- def completer(sym: Symbol): Type = ???
- def derivedSym: Symbol = ???
- def derivedTree: DefDef = ???
- def flagsExtra: Long = ???
- def flagsMask: Long = ???
- def name: TermName = ???
- }
-
+ case class ImplicitClassWrapper(tree: ClassDef) extends DerivedFromClassDef {
+ def completer(sym: Symbol): Type = ??? // not needed
+ def createAndEnterSymbol(): Symbol = enterSyntheticSym(derivedTree)
+ def derivedSym: Symbol = {
+ val result = enclClass.info decl name
+ assert(result != NoSymbol, "not found: "+name+" in "+enclClass+" "+enclClass.info.decls)
+ result
+ }
+ def derivedTree: DefDef =
+ factoryMeth(mods & flagsMask | flagsExtra, name, tree, symbolic = false)
+ def flagsExtra: Long = METHOD | IMPLICIT
+ def flagsMask: Long = AccessFlags
+ def name: TermName = tree.name.toTermName
+ }
+
case class Getter(tree: ValDef) extends DerivedGetter {
def name = tree.name
def category = GetterTargetClass
@@ -374,7 +412,7 @@ trait MethodSynthesis {
case ExistentialType(_, _) => TypeTree()
case tp => TypeTree(tp)
}
- tpt setPos focusPos(derivedSym.pos)
+ tpt setPos derivedSym.pos.focus
// keep type tree of original abstract field
if (mods.isDeferred)
tpt setOriginal tree.tpt
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 1b505d1e5d..ffd00751e0 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -99,7 +99,7 @@ trait Namers extends MethodSynthesis {
owner.unsafeTypeParams foreach (paramContext.scope enter _)
newNamer(paramContext)
}
-
+
def enclosingNamerWithScope(scope: Scope) = {
var cx = context
while (cx != NoContext && cx.scope != scope) cx = cx.outer
@@ -529,7 +529,7 @@ trait Namers extends MethodSynthesis {
def enterCopyMethodOrGetter(tree: Tree, tparams: List[TypeDef]): Symbol = {
val sym = tree.symbol
val lazyType = completerOf(tree, tparams)
- def completeCopyFirst = sym.isSynthetic && (!sym.hasDefaultFlag || sym.owner.info.member(nme.copy).isSynthetic)
+ def completeCopyFirst = sym.isSynthetic && (!sym.hasDefault || sym.owner.info.member(nme.copy).isSynthetic)
def completeCopyMethod(clazz: Symbol) {
// the 'copy' method of case classes needs a special type completer to make
// bug0054.scala (and others) work. the copy method has to take exactly the same
@@ -624,11 +624,6 @@ trait Namers extends MethodSynthesis {
enterCopyMethodOrGetter(tree, tparams)
else
sym setInfo completerOf(tree, tparams)
-
- if (mods hasFlag MACRO) {
- if (!(sym.owner.isClass && sym.owner.isStatic))
- context.error(tree.pos, "macro definition must appear in globally accessible class")
- }
}
def enterClassDef(tree: ClassDef) {
@@ -651,14 +646,6 @@ trait Namers extends MethodSynthesis {
val m = ensureCompanionObject(tree)
classAndNamerOfModule(m) = (tree, null)
}
- val hasMacro = impl.body exists {
- case DefDef(mods, _, _, _, _, _) => mods hasFlag MACRO
- case _ => false
- }
- if (hasMacro) {
- val m = ensureCompanionObject(tree)
- classOfModuleClass(m.moduleClass) = new WeakReference(tree)
- }
val owner = tree.symbol.owner
if (owner.isPackageObjectClass) {
context.unit.warning(tree.pos,
@@ -666,10 +653,12 @@ trait Namers extends MethodSynthesis {
"If possible, define " + tree.symbol + " in " + owner.skipPackageObject + " instead."
)
}
-
+
// Suggested location only.
- if (mods.isImplicit)
- enterImplicitClass(tree)
+ if (mods.isImplicit) {
+ log("enter implicit wrapper "+tree+", owner = "+owner)
+ enterImplicitWrapper(tree)
+ }
}
// this logic is needed in case typer was interrupted half
@@ -684,7 +673,7 @@ trait Namers extends MethodSynthesis {
val acc = sym.lazyAccessor
if (acc != NoSymbol) enterIfNotThere(acc)
}
- defaultParametersOfMethod(sym) foreach enterIfNotThere
+ defaultParametersOfMethod(sym) foreach { symRef => enterIfNotThere(symRef()) }
}
this.context
}
@@ -809,7 +798,9 @@ trait Namers extends MethodSynthesis {
*/
private def assignTypeToTree(tree: ValOrDefDef, defnTyper: Typer, pt: Type): Type = {
// compute result type from rhs
- val typedBody = defnTyper.computeType(tree.rhs, pt)
+ val typedBody =
+ if (tree.symbol.isTermMacro) defnTyper.computeMacroDefType(tree, pt)
+ else defnTyper.computeType(tree.rhs, pt)
val sym = if (owner.isMethod) owner else tree.symbol
val typedDefn = widenIfNecessary(sym, typedBody, pt)
assignTypeToTree(tree, typedDefn)
@@ -831,19 +822,17 @@ trait Namers extends MethodSynthesis {
if (!hasType)
tpt defineType NoType
- if (hasType || hasName) {
- owner.typeOfThis =
- if (hasType) selfTypeCompleter(tpt)
- else owner.tpe
- }
val sym = (
- if (hasType) owner.thisSym setPos self.pos
- else if (hasName) owner.thisSym
- else owner.newThisSym(self.pos) setInfo owner.tpe
+ if (hasType || hasName) {
+ owner.typeOfThis = if (hasType) selfTypeCompleter(tpt) else owner.tpe
+ val selfSym = owner.thisSym setPos self.pos
+ if (hasName) selfSym setName name else selfSym
+ }
+ else {
+ val symName = if (name != nme.WILDCARD) name else nme.this_
+ owner.newThisSym(symName, owner.pos) setInfo owner.tpe
+ }
)
- if (hasName)
- sym.name = name
-
self.symbol = context.scope enter sym
}
@@ -873,10 +862,8 @@ trait Namers extends MethodSynthesis {
Namers.this.classOfModuleClass get clazz foreach { cdefRef =>
val cdef = cdefRef()
if (cdef.mods.isCase) addApplyUnapply(cdef, templateNamer)
- if (settings.Xmacros.value) addMacroMethods(cdef.impl, templateNamer)
classOfModuleClass -= clazz
}
- if (settings.Xmacros.value) addMacroMethods(templ, templateNamer)
}
// add the copy method to case classes; this needs to be done here, not in SyntheticMethods, because
@@ -1031,12 +1018,20 @@ trait Namers extends MethodSynthesis {
}
addDefaultGetters(meth, vparamss, tparams, overriddenSymbol)
+ // macro defs need to be typechecked in advance
+ // because @macroImpl annotation only gets assigned during typechecking
+ // otherwise we might find ourselves in the situation when we specified -Xmacro-fallback-classpath
+ // but macros still don't expand
+ // that might happen because macro def doesn't have its link a macro impl yet
+ if (ddef.symbol.isTermMacro) {
+ val pt = resultPt.substSym(tparamSyms, tparams map (_.symbol))
+ typer.computeMacroDefType(ddef, pt)
+ }
+
thisMethodType({
val rt = (
if (!tpt.isEmpty) {
typer.typedType(tpt).tpe
- } else if (meth.isMacro) {
- assignTypeToTree(ddef, AnyClass.tpe)
} else {
// replace deSkolemized symbols with skolemized ones
// (for resultPt computed by looking at overridden symbol, right?)
@@ -1045,7 +1040,7 @@ trait Namers extends MethodSynthesis {
}
)
// #2382: return type of default getters are always @uncheckedVariance
- if (meth.hasDefaultFlag)
+ if (meth.hasDefault)
rt.withAnnotation(AnnotationInfo(uncheckedVarianceClass.tpe, List(), List()))
else rt
})
@@ -1095,8 +1090,8 @@ trait Namers extends MethodSynthesis {
for (vparam <- vparams) {
val sym = vparam.symbol
// true if the corresponding parameter of the base class has a default argument
- val baseHasDefault = overrides && baseParams.head.hasDefaultFlag
- if (sym.hasDefaultFlag) {
+ val baseHasDefault = overrides && baseParams.head.hasDefault
+ if (sym.hasDefault) {
// generate a default getter for that argument
val oflag = if (baseHasDefault) OVERRIDE else 0
val name = nme.defaultGetterName(meth.name, posCounter)
@@ -1163,7 +1158,7 @@ trait Namers extends MethodSynthesis {
// if compiling the same local block several times (which can happen in interactive mode)
// we might otherwise not find the default symbol, because the second time it the
// method symbol will be re-entered in the scope but the default parameter will not.
- defaultParametersOfMethod(meth) += default
+ defaultParametersOfMethod(meth) += new WeakReference(default)
}
} else if (baseHasDefault) {
// the parameter does not have a default itself, but the
@@ -1362,7 +1357,7 @@ trait Namers extends MethodSynthesis {
}
}
private val logDefinition = new LogTransitions[Symbol](
- sym => "[define] >> " + sym.defaultFlagString + " " + sym.fullLocationString,
+ sym => "[define] >> " + sym.flagString + " " + sym.fullLocationString,
sym => "[define] << " + sym
)
private def logAndValidate(sym: Symbol)(body: => Unit) {
@@ -1406,10 +1401,10 @@ trait Namers extends MethodSynthesis {
if (sym.isImplicit) {
if (sym.isConstructor)
fail(ImplicitConstr)
- if (!sym.isTerm)
- fail(ImplicitNotTerm)
+ if (!(sym.isTerm || (sym.isClass && !sym.isTrait)))
+ fail(ImplicitNotTermOrClass)
if (sym.owner.isPackageClass)
- fail(ImplicitTopObject)
+ fail(ImplicitAtToplevel)
}
if (sym.isClass) {
if (sym.isAnyOverride && !sym.hasFlag(TRAIT))
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index c621497618..4d84bf4af2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -8,6 +8,7 @@ package typechecker
import symtab.Flags._
import scala.collection.mutable
+import scala.ref.WeakReference
/**
* @author Lukas Rytz
@@ -20,7 +21,7 @@ trait NamesDefaults { self: Analyzer =>
import NamesDefaultsErrorsGen._
val defaultParametersOfMethod =
- perRunCaches.newWeakMap[Symbol, Set[Symbol]]() withDefaultValue Set()
+ perRunCaches.newWeakMap[Symbol, Set[WeakReference[Symbol]]]() withDefaultValue Set()
case class NamedApplyInfo(
qual: Option[Tree],
@@ -377,7 +378,7 @@ trait NamesDefaults { self: Analyzer =>
pos: util.Position, context: Context): (List[Tree], List[Symbol]) = {
if (givenArgs.length < params.length) {
val (missing, positional) = missingParams(givenArgs, params)
- if (missing forall (_.hasDefaultFlag)) {
+ if (missing forall (_.hasDefault)) {
val defaultArgs = missing flatMap (p => {
val defGetter = defaultGetter(p, context)
// TODO #3649 can create spurious errors when companion object is gone (because it becomes unlinked from scope)
@@ -399,7 +400,7 @@ trait NamesDefaults { self: Analyzer =>
}
})
(givenArgs ::: defaultArgs, Nil)
- } else (givenArgs, missing filterNot (_.hasDefaultFlag))
+ } else (givenArgs, missing filterNot (_.hasDefault))
} else (givenArgs, Nil)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 54b711cebc..ad727d4082 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -123,7 +123,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
defaultMethodNames.distinct foreach { name =>
val methods = clazz.info.findMember(name, 0L, METHOD, false).alternatives
- val haveDefaults = methods filter (sym => sym.hasParamWhich(_.hasDefaultFlag) && !nme.isProtectedAccessorName(sym.name))
+ val haveDefaults = methods filter (sym => sym.hasParamWhich(_.hasDefault) && !nme.isProtectedAccessorName(sym.name))
if (haveDefaults.lengthCompare(1) > 0) {
val owners = haveDefaults map (_.owner)
@@ -227,6 +227,8 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
* 1.8.1 M's type is a subtype of O's type, or
* 1.8.2 M is of type []S, O is of type ()T and S <: T, or
* 1.8.3 M is of type ()S, O is of type []T and S <: T, or
+ * 1.9. If M is a macro def, O cannot be deferred.
+ * 1.10. If M is not a macro def, O cannot be a macro def.
* 2. Check that only abstract classes have deferred members
* 3. Check that concrete classes do not have deferred definitions
* that are not implemented in a subclass.
@@ -381,7 +383,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
overrideError("cannot be used here - class definitions cannot be overridden");
} else if (!other.isDeferred && member.isClass) {
overrideError("cannot be used here - classes can only override abstract types");
- } else if (other.isFinal) { // (1.2)
+ } else if (other.isEffectivelyFinal) { // (1.2)
overrideError("cannot override final member");
// synthetic exclusion needed for (at least) default getters.
} else if (!other.isDeferred && !member.isAnyOverride && !member.isSynthetic) {
@@ -416,6 +418,10 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
} else if (other.isValue && other.isLazy && !other.isSourceMethod && !other.isDeferred &&
member.isValue && !member.isLazy) {
overrideError("must be declared lazy to override a concrete lazy value")
+ } else if (other.isDeferred && member.isTermMacro) { // (1.9)
+ overrideError("cannot override an abstract method")
+ } else if (other.isTermMacro && !member.isTermMacro) { // (1.10)
+ overrideError("cannot override a macro")
} else {
checkOverrideTypes()
if (settings.warnNullaryOverride.value) {
@@ -662,7 +668,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
}
// Check the remainder for invalid absoverride.
- for (member <- rest ; if ((member hasFlag ABSOVERRIDE) && member.isIncompleteIn(clazz))) {
+ for (member <- rest ; if (member.isAbstractOverride && member.isIncompleteIn(clazz))) {
val other = member.superSymbol(clazz)
val explanation =
if (other != NoSymbol) " and overrides incomplete superclass member " + infoString(other)
@@ -756,11 +762,10 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
// 4. Check that every defined member with an `override` modifier overrides some other member.
for (member <- clazz.info.decls)
- if ((member hasFlag (OVERRIDE | ABSOVERRIDE)) &&
- !(clazz.thisType.baseClasses exists (hasMatchingSym(_, member)))) {
+ if (member.isAnyOverride && !(clazz.thisType.baseClasses exists (hasMatchingSym(_, member)))) {
// for (bc <- clazz.info.baseClasses.tail) Console.println("" + bc + " has " + bc.info.decl(member.name) + ":" + bc.info.decl(member.name).tpe);//DEBUG
unit.error(member.pos, member.toString() + " overrides nothing");
- member resetFlag OVERRIDE
+ member resetFlag (OVERRIDE | ABSOVERRIDE) // Any Override
}
}
@@ -1054,10 +1059,17 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
/** Symbols which limit the warnings we can issue since they may be value types */
val isMaybeValue = Set(AnyClass, AnyRefClass, AnyValClass, ObjectClass, ComparableClass, JavaSerializableClass)
- // Whether def equals(other: Any) is overridden or synthetic
+ // Whether def equals(other: Any) has known behavior: it is the default
+ // inherited from java.lang.Object, or it is a synthetically generated
+ // case equals. TODO - more cases are warnable if the target is a synthetic
+ // equals.
def isUsingWarnableEquals = {
val m = receiver.info.member(nme.equals_)
- (m == Object_equals) || (m == Any_equals) || (m.isSynthetic && m.owner.isCase)
+ def n = actual.info.member(nme.equals_)
+ ( (m == Object_equals)
+ || (m == Any_equals)
+ || (m.isSynthetic && m.owner.isCase && !n.owner.isCase)
+ )
}
// Whether this == or != is one of those defined in Any/AnyRef or an overload from elsewhere.
def isUsingDefaultScalaOp = {
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 94733369a8..43cbea83ff 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -121,7 +121,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
if (sym.isDeferred) {
val member = sym.overridingSymbol(clazz);
if (mix != tpnme.EMPTY || member == NoSymbol ||
- !((member hasFlag ABSOVERRIDE) && member.isIncompleteIn(clazz)))
+ !(member.isAbstractOverride && member.isIncompleteIn(clazz)))
unit.error(sel.pos, ""+sym.fullLocationString+" is accessed from super. It may not be abstract "+
"unless it is overridden by a member declared `abstract' and `override'");
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
index 105c2c0b98..8895905ca7 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
@@ -14,6 +14,20 @@ import util.returning
abstract class TreeCheckers extends Analyzer {
import global._
+ private val everything = ListBuffer[(Phase, Map[Tree, (Symbol, Type)])]()
+ private val currentTrees = mutable.Map[Tree, (Symbol, Type)]()
+
+ if (settings.debug.value) {
+ sys addShutdownHook {
+ for ((ph, map) <- everything.toList) {
+ println("\n>>>> " + ph + "\n")
+ for ((tree, (sym, tpe)) <- map.toList.sortBy(_._1.summaryString)) {
+ println("%20s %20s %s".format(sym, tpe, ("" + tree) take 50))
+ }
+ }
+ }
+ }
+
private def classstr(x: AnyRef) = x.getClass.getName split """\\.|\\$""" last;
private def typestr(x: Type) = " (tpe = " + x + ")"
private def treestr(t: Tree) = t + " [" + classstr(t) + "]" + typestr(t.tpe)
@@ -92,11 +106,16 @@ abstract class TreeCheckers extends Analyzer {
if (maps.isEmpty || maps.last._1 != ph)
maps += ((ph, new PhaseMap))
+ currentTrees.clear()
traverse(unit.body)
+ everything += ((ph, currentTrees.toMap))
+
reportChanges()
}
override def traverse(tree: Tree): Unit = {
val sym = tree.symbol
+ currentTrees(tree) = ((sym, tree.tpe))
+
if (sym != null && sym != NoSymbol) {
record(sym, tree)
tree match {
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index 6efa595d99..38c2c5f719 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -270,8 +270,7 @@ trait TypeDiagnostics {
private val savedName = sym.name
def restoreName() = sym.name = savedName
def isAltered = sym.name != savedName
- def modifyName(f: String => String) =
- sym.name = newTypeName(f(sym.name.toString))
+ def modifyName(f: String => String) = sym setName newTypeName(f(sym.name.toString))
/** Prepend java.lang, scala., or Predef. if this type originated
* in one of those.
@@ -457,14 +456,20 @@ trait TypeDiagnostics {
ex match {
case CyclicReference(sym, info: TypeCompleter) =>
- val pos = info.tree match {
- case Import(expr, _) => expr.pos
- case _ => ex.pos
+ if (context0.owner.isTermMacro) {
+ // see comments to TypeSigError for an explanation of this special case
+ // [Eugene] is there a better way?
+ throw ex
+ } else {
+ val pos = info.tree match {
+ case Import(expr, _) => expr.pos
+ case _ => ex.pos
+ }
+ contextError(context0, pos, cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage())
+
+ if (sym == ObjectClass)
+ throw new FatalError("cannot redefine root "+sym)
}
- contextError(context0, pos, cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage())
-
- if (sym == ObjectClass)
- throw new FatalError("cannot redefine root "+sym)
case _ =>
contextError(context0, ex.pos, ex)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 19d7dde875..3a5abb4cea 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -51,6 +51,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
transformed.clear()
}
+ // [Eugene] shouldn't this be converted to resetAllAttrs?
object UnTyper extends Traverser {
override def traverse(tree: Tree) = {
if (tree != EmptyTree) tree.tpe = null
@@ -181,12 +182,15 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case _ =>
def wrapImplicit(from: Type): Tree = {
val result = inferImplicit(tree, functionType(List(from), to), reportAmbiguous, true, context, saveErrors)
- if (result.subst != EmptyTreeTypeSubstituter) result.subst traverse tree
+ if (result.subst != EmptyTreeTypeSubstituter) {
+ result.subst traverse tree
+ notifyUndetparamsInferred(result.subst.from, result.subst.to)
+ }
result.tree
}
val result = wrapImplicit(from)
if (result != EmptyTree) result
- else wrapImplicit(appliedType(ByNameParamClass.typeConstructor, List(from)))
+ else wrapImplicit(byNameType(from))
}
}
@@ -844,7 +848,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case Block(_, tree1) => tree1.symbol
case _ => tree.symbol
}
- if (!meth.isConstructor && !meth.isMacro && isFunctionType(pt)) { // (4.2)
+ if (!meth.isConstructor && !meth.isTermMacro && isFunctionType(pt)) { // (4.2)
debuglog("eta-expanding " + tree + ":" + tree.tpe + " to " + pt)
checkParamsConvertible(tree, tree.tpe)
val tree0 = etaExpand(context.unit, tree)
@@ -1039,12 +1043,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
else TypeApply(tree, tparams1 map (tparam =>
TypeTree(tparam.tpeHK) setPos tree.pos.focus)) setPos tree.pos //@M/tcpolyinfer: changed tparam.tpe to tparam.tpeHK
context.undetparams ++= tparams1
+ notifyUndetparamsAdded(tparams1)
adapt(tree1 setType restpe.substSym(tparams, tparams1), mode, pt, original)
case mt: MethodType if mt.isImplicit && ((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) => // (4.1)
adaptToImplicitMethod(mt)
case mt: MethodType if (((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) &&
- (context.undetparams.isEmpty || inPolyMode(mode))) =>
+ (context.undetparams.isEmpty || inPolyMode(mode))) && !(tree.symbol != null && tree.symbol.isTermMacro) =>
instantiateToMethodType(mt)
case _ =>
@@ -1057,13 +1062,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
if (tree.isType)
adaptType()
- else if (inExprModeButNot(mode, FUNmode) && tree.symbol != null && tree.symbol.isMacro && !tree.isDef && !(tree exists (_.isErroneous)))
- macroExpand(tree, this) match {
- case Some(expanded: Tree) =>
- typed(expanded, mode, pt)
- case None =>
- setError(tree) // error already reported
- }
+ else if (context.macrosEnabled && // when macros are enabled
+ inExprModeButNot(mode, FUNmode) && !tree.isDef && // and typechecking application
+ tree.symbol != null && tree.symbol.isTermMacro) // of a term macro
+ macroExpand(this, tree, pt)
else if ((mode & (PATTERNmode | FUNmode)) == (PATTERNmode | FUNmode))
adaptConstrPattern()
else if (inAllModes(mode, EXPRmode | FUNmode) &&
@@ -1684,7 +1686,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val body =
if (isPastTyper || reporter.hasErrors) templ.body
- else templ.body flatMap rewrappingWrapperTrees(namer.finishGetterSetter(Typer.this, _))
+ else templ.body flatMap rewrappingWrapperTrees(namer.addDerivedTrees(Typer.this, _))
val body1 = typedStats(body, templ.symbol)
@@ -1937,8 +1939,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
meth.owner.isAnonOrRefinementClass))
InvalidConstructorDefError(ddef)
typed(ddef.rhs)
- } else if (meth.isMacro) {
- EmptyTree
+ } else if (meth.isTermMacro) {
+ // typechecking macro bodies is sort of unconventional
+ // that's why we employ our custom typing scheme orchestrated outside of the typer
+ transformedOr(ddef.rhs, typedMacroBody(this, ddef))
} else {
transformedOrTyped(ddef.rhs, EXPRmode, tpt1.tpe)
}
@@ -1953,7 +1957,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
rhs1 = checkDead(rhs1)
if (!isPastTyper && meth.owner.isClass &&
- meth.paramss.exists(ps => ps.exists(_.hasDefaultFlag) && isRepeatedParamType(ps.last.tpe)))
+ meth.paramss.exists(ps => ps.exists(_.hasDefault) && isRepeatedParamType(ps.last.tpe)))
StarWithDefaultError(meth)
if (!isPastTyper) {
@@ -2208,8 +2212,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def translateMatch(selector1: Tree, selectorTp: Type, casesAdapted: List[CaseDef], ownType: Type, doTranslation: Boolean, matchFailGen: Option[Tree => Tree] = None) = {
def repeatedToSeq(tp: Type): Type = (tp baseType RepeatedParamClass) match {
- case TypeRef(_, RepeatedParamClass, args) => appliedType(SeqClass.typeConstructor, args)
- case _ => tp
+ case TypeRef(_, RepeatedParamClass, arg :: Nil) => seqType(arg)
+ case _ => tp
}
if (!doTranslation) { // a switch
@@ -2244,7 +2248,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
vparams map {p => if(p.tpt.tpe == null) typedType(p.tpt).tpe else p.tpt.tpe}
}
- def mkParams(methodSym: Symbol, formals: List[Type]/* = deriveFormals*/) = {
+ def mkParams(methodSym: Symbol, formals: List[Type] = deriveFormals) = {
selOverride match {
case None if targs.isEmpty => MissingParameterTypeAnonMatchError(tree, pt); (Nil, EmptyTree)
case None =>
@@ -2254,7 +2258,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
(ps, sel)
case Some((vparams, sel)) =>
val newParamSyms = (vparams, formals).zipped map {(p, tp) =>
- methodSym.newValueParameter(p.name, focusPos(p.pos), SYNTHETIC) setInfo tp
+ methodSym.newValueParameter(p.name, p.pos.focus, SYNTHETIC) setInfo tp
}
(newParamSyms, sel.duplicate)
@@ -2270,7 +2274,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// rig the show so we can get started typing the method body -- later we'll correct the infos...
anonClass setInfo ClassInfoType(List(ObjectClass.tpe, pt, SerializableClass.tpe), newScope, anonClass)
val methodSym = anonClass.newMethod(nme.apply, tree.pos, FINAL)
- val (paramSyms, selector) = mkParams(methodSym, deriveFormals)
+ val (paramSyms, selector) = mkParams(methodSym)
if (selector eq EmptyTree) EmptyTree
else {
@@ -2282,7 +2286,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, cases, mode, ptRes)
val methFormals = paramSyms map (_.tpe)
- val parents = List(appliedType(AbstractFunctionClass(arity).typeConstructor, methFormals :+ resTp), SerializableClass.tpe)
+ val parents = List(abstractFunctionType(methFormals, resTp), SerializableClass.tpe)
anonClass setInfo ClassInfoType(parents, newScope, anonClass)
methodSym setInfoAndEnter MethodType(paramSyms, resTp)
@@ -2309,7 +2313,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
else {
// applyOrElse's default parameter:
val B1 = methodSym newTypeParameter(newTypeName("B1")) setInfo TypeBounds.empty //lower(resTp)
- val default = methodSym newValueParameter(newTermName("default"), focusPos(tree.pos), SYNTHETIC) setInfo functionType(List(A1.tpe), B1.tpe)
+ val default = methodSym newValueParameter(newTermName("default"), tree.pos.focus, SYNTHETIC) setInfo functionType(List(A1.tpe), B1.tpe)
val paramSyms = List(x, default)
methodSym setInfoAndEnter polyType(List(A1, B1), MethodType(paramSyms, B1.tpe))
@@ -2334,7 +2338,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def isDefinedAtMethod = {
val methodSym = anonClass.newMethod(nme.isDefinedAt, tree.pos, FINAL)
- val (paramSyms, selector) = mkParams(methodSym, deriveFormals)
+ val (paramSyms, selector) = mkParams(methodSym)
if (selector eq EmptyTree) EmptyTree
else {
val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it)
@@ -2516,54 +2520,53 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
|| (looker.hasAccessorFlag && !accessed.hasAccessorFlag && accessed.isPrivate)
)
- def checkNoDoubleDefsAndAddSynthetics(stats: List[Tree]): List[Tree] = {
+ def checkNoDoubleDefs(stats: List[Tree]): Unit = {
val scope = if (inBlock) context.scope else context.owner.info.decls
- var newStats = new ListBuffer[Tree]
- var needsCheck = true
- var moreToAdd = true
- while (moreToAdd) {
- val initSize = scope.size
- var e = scope.elems
- while ((e ne null) && e.owner == scope) {
-
- // check no double def
- if (needsCheck) {
- var e1 = scope.lookupNextEntry(e)
- while ((e1 ne null) && e1.owner == scope) {
- if (!accesses(e.sym, e1.sym) && !accesses(e1.sym, e.sym) &&
- (e.sym.isType || inBlock || (e.sym.tpe matches e1.sym.tpe) || e.sym.isMacro && e1.sym.isMacro))
- // default getters are defined twice when multiple overloads have defaults. an
- // error for this is issued in RefChecks.checkDefaultsInOverloaded
- if (!e.sym.isErroneous && !e1.sym.isErroneous && !e.sym.hasDefaultFlag &&
- !e.sym.hasAnnotation(BridgeClass) && !e1.sym.hasAnnotation(BridgeClass)) {
- log("Double definition detected:\n " +
- ((e.sym.getClass, e.sym.info, e.sym.ownerChain)) + "\n " +
- ((e1.sym.getClass, e1.sym.info, e1.sym.ownerChain)))
-
- DefDefinedTwiceError(e.sym, e1.sym)
- scope.unlink(e1) // need to unlink to avoid later problems with lub; see #2779
- }
- e1 = scope.lookupNextEntry(e1)
+ var e = scope.elems
+ while ((e ne null) && e.owner == scope) {
+ var e1 = scope.lookupNextEntry(e)
+ while ((e1 ne null) && e1.owner == scope) {
+ if (!accesses(e.sym, e1.sym) && !accesses(e1.sym, e.sym) &&
+ (e.sym.isType || inBlock || (e.sym.tpe matches e1.sym.tpe)))
+ // default getters are defined twice when multiple overloads have defaults. an
+ // error for this is issued in RefChecks.checkDefaultsInOverloaded
+ if (!e.sym.isErroneous && !e1.sym.isErroneous && !e.sym.hasDefaultFlag &&
+ !e.sym.hasAnnotation(BridgeClass) && !e1.sym.hasAnnotation(BridgeClass)) {
+ log("Double definition detected:\n " +
+ ((e.sym.getClass, e.sym.info, e.sym.ownerChain)) + "\n " +
+ ((e1.sym.getClass, e1.sym.info, e1.sym.ownerChain)))
+
+ DefDefinedTwiceError(e.sym, e1.sym)
+ scope.unlink(e1) // need to unlink to avoid later problems with lub; see #2779
}
- }
-
- // add synthetics
- context.unit.synthetics get e.sym foreach { tree =>
- newStats += typedStat(tree) // might add even more synthetics to the scope
- context.unit.synthetics -= e.sym
+ e1 = scope.lookupNextEntry(e1)
}
-
e = e.next
}
- needsCheck = false
- // the type completer of a synthetic might add more synthetics. example: if the
- // factory method of a case class (i.e. the constructor) has a default.
- moreToAdd = initSize != scope.size
+ }
+
+ def addSynthetics(stats: List[Tree]): List[Tree] = {
+ val scope = if (inBlock) context.scope else context.owner.info.decls
+ var newStats = new ListBuffer[Tree]
+ var moreToAdd = true
+ while (moreToAdd) {
+ val initElems = scope.elems
+ for (sym <- scope)
+ for (tree <- context.unit.synthetics get sym) {
+ newStats += typedStat(tree) // might add even more synthetics to the scope
+ context.unit.synthetics -= sym
+ }
+ // the type completer of a synthetic might add more synthetics. example: if the
+ // factory method of a case class (i.e. the constructor) has a default.
+ moreToAdd = scope.elems ne initElems
}
if (newStats.isEmpty) stats
else {
// put default getters next to the method they belong to,
// same for companion objects. fixes #2489 and #4036.
+ // [Martin] This is pretty ugly. I think we could avoid
+ // this code by associating defaults and companion objects
+ // with the original tree instead of the new symbol.
def matches(stat: Tree, synt: Tree) = (stat, synt) match {
case (DefDef(_, statName, _, _, _, _), DefDef(mods, syntName, _, _, _, _)) =>
mods.hasDefaultFlag && syntName.toString.startsWith(statName.toString)
@@ -2593,7 +2596,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
context.updateBuffer(statsErrors)
if (phase.erasedTypes) stats1
- else checkNoDoubleDefsAndAddSynthetics(stats1)
+ else {
+ checkNoDoubleDefs(stats1)
+ addSynthetics(stats1)
+ }
}
def typedArg(arg: Tree, mode: Int, newmode: Int, pt: Type): Tree = {
@@ -2617,7 +2623,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
else if (isByNameParamType(formals.head)) 0
else BYVALmode
)
- val tree = typedArg(args.head, mode, typedMode, adapted.head)
+ var tree = typedArg(args.head, mode, typedMode, adapted.head)
+ if (hasPendingMacroExpansions) tree = macroExpandAll(this, tree)
// formals may be empty, so don't call tail
tree :: loop(args.tail, formals drop 1, adapted.tail)
}
@@ -2779,6 +2786,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def tryNamesDefaults: Tree = {
val lencmp = compareLengths(args, formals)
+ def checkNotMacro() = {
+ if (fun.symbol != null && fun.symbol.filter(sym => sym != null && sym.isTermMacro) != NoSymbol)
+ duplErrorTree(NamedAndDefaultArgumentsNotSupportedForMacros(tree, fun))
+ }
+
if (mt.isErroneous) duplErrTree
else if (inPatternMode(mode)) {
// #2064
@@ -2797,8 +2809,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
else if (isIdentity(argPos) && !isNamedApplyBlock(fun)) {
// if there's no re-ordering, and fun is not transformed, no need to transform
// more than an optimization, e.g. important in "synchronized { x = update-x }"
+ checkNotMacro()
doTypedApply(tree, fun, namelessArgs, mode, pt)
} else {
+ checkNotMacro()
transformNamedApplication(Typer.this, mode, pt)(
treeCopy.Apply(tree, fun, namelessArgs), argPos)
}
@@ -2806,6 +2820,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// defaults are needed. they are added to the argument list in named style as
// calls to the default getters. Example:
// foo[Int](a)() ==> foo[Int](a)(b = foo$qual.foo$default$2[Int](a))
+ checkNotMacro()
val fun1 = transformNamedApplication(Typer.this, mode, pt)(fun, x => x)
if (fun1.isErroneous) duplErrTree
else {
@@ -3148,12 +3163,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
for (sym <- names) {
// make sure the flags are up to date before erroring (jvm/t3415 fails otherwise)
sym.initialize
- if (!sym.hasAnnotation(AnnotationDefaultAttr) && !sym.hasDefaultFlag)
+ if (!sym.hasAnnotation(AnnotationDefaultAttr) && !sym.hasDefault)
reportAnnotationError(AnnotationMissingArgError(ann, annType, sym))
}
if (hasError) annotationError
- else AnnotationInfo(annType, List(), nvPairs map {p => (p._1, p._2.get)}).setOriginal(ann).setPos(ann.pos)
+ else AnnotationInfo(annType, List(), nvPairs map {p => (p._1, p._2.get)}).setOriginal(Apply(typedFun, args)).setPos(ann.pos)
}
} else if (requireJava) {
reportAnnotationError(NestedAnnotationError(ann, annType))
@@ -3193,7 +3208,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def annInfo(t: Tree): AnnotationInfo = t match {
case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) =>
- AnnotationInfo(annType, args, List()).setOriginal(ann).setPos(t.pos)
+ AnnotationInfo(annType, args, List()).setOriginal(typedAnn).setPos(t.pos)
case Block(stats, expr) =>
context.warning(t.pos, "Usage of named or default arguments transformed this annotation\n"+
@@ -3479,7 +3494,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
println(s)
}
- protected def typed1(tree: Tree, mode: Int, pt: Type): Tree = {
+ def typed1(tree: Tree, mode: Int, pt: Type): Tree = {
def isPatternMode = inPatternMode(mode)
//Console.println("typed1("+tree.getClass()+","+Integer.toHexString(mode)+","+pt+")")
@@ -3493,10 +3508,27 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
def typedAnnotated(ann: Tree, arg1: Tree): Tree = {
- def mkTypeTree(tpe: Type) = TypeTree(tpe) setOriginal tree setPos tree.pos.focus
/** mode for typing the annotation itself */
val annotMode = mode & ~TYPEmode | EXPRmode
+ def resultingTypeTree(tpe: Type) = {
+ // we need symbol-ful originals for reification
+ // hence we go the extra mile to hand-craft tis guy
+ val original =
+ if (arg1.isType)
+ (tree, arg1) match {
+ case (Annotated(annot, arg), tt @ TypeTree()) => Annotated(annot, tt.original)
+ // this clause is needed to correctly compile stuff like "new C @D" or "@(inline @getter)"
+ case (Annotated(annot, arg), _) => Annotated(annot, arg1)
+ case _ => throw new Error("unexpected trees in typedAnnotated: tree = %s, arg1 = %s".format(showRaw(tree), showRaw(arg1)))
+ }
+ else
+ tree
+ original setType ann.tpe
+ original setPos tree.pos.focus
+ TypeTree(tpe) setOriginal original setPos tree.pos.focus
+ }
+
if (arg1.isType) {
// make sure the annotation is only typechecked once
if (ann.tpe == null) {
@@ -3539,11 +3571,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
arg1 // simply drop erroneous annotations
else {
ann.tpe = atype
- mkTypeTree(atype)
+ resultingTypeTree(atype)
}
} else {
// the annotation was typechecked before
- mkTypeTree(ann.tpe)
+ resultingTypeTree(ann.tpe)
}
}
else {
@@ -3552,7 +3584,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
ann.tpe = arg1.tpe.withAnnotation(annotInfo)
}
val atype = ann.tpe
- Typed(arg1, mkTypeTree(atype)) setPos tree.pos setType atype
+ Typed(arg1, resultingTypeTree(atype)) setPos tree.pos.focus setType atype
}
}
@@ -3597,7 +3629,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
treeCopy.ArrayValue(tree, elemtpt1, elems1)
.setType(
(if (isFullyDefined(pt) && !phase.erasedTypes) pt
- else appliedType(ArrayClass.typeConstructor, List(elemtpt1.tpe))).notNull)
+ else arrayType(elemtpt1.tpe)).notNull)
}
def typedAssign(lhs: Tree, rhs: Tree): Tree = {
@@ -3718,6 +3750,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (checkStablePrefixClassType(tpt0))
if (tpt0.hasSymbol && !tpt0.symbol.typeParams.isEmpty) {
context.undetparams = cloneSymbols(tpt0.symbol.typeParams)
+ notifyUndetparamsAdded(context.undetparams)
TypeTree().setOriginal(tpt0)
.setType(appliedType(tpt0.tpe, context.undetparams map (_.tpeHK))) // @PP: tpeHK! #3343, #4018, #4347.
} else tpt0
@@ -4576,7 +4609,18 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
typedNew(tpt)
case Typed(expr, Function(List(), EmptyTree)) =>
- typedEta(checkDead(typed1(expr, mode, pt)))
+ // find out whether the programmer is trying to eta-expand a macro def
+ // to do that we need to typecheck the tree first (we need a symbol of the eta-expandee)
+ // that typecheck must not trigger macro expansions, so we explicitly prohibit them
+ // Q: "but, " - you may ask - ", `typed1` doesn't call adapt, which does macro expansion, so why explicit check?"
+ // A: solely for robustness reasons. this mechanism might change in the future, which might break unprotected code
+ val expr1 = context.withMacrosDisabled(typed1(expr, mode, pt))
+ expr1 match {
+ case macroDef if macroDef.symbol.isTermMacro =>
+ MacroEtaError(expr1)
+ case _ =>
+ typedEta(checkDead(expr1))
+ }
case Typed(expr0, tpt @ Ident(tpnme.WILDCARD_STAR)) =>
val expr = typed(expr0, onlyStickyModes(mode), WildcardType)
@@ -4650,18 +4694,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
tpt.tpe.typeSymbol == ArrayClass &&
args.length == 1 &&
erasure.GenericArray.unapply(tpt.tpe).isDefined) => // !!! todo simplify by using extractor
- // convert new Array[T](len) to evidence[ClassManifest[T]].newArray(len)
- // convert new Array^N[T](len) for N > 1 to evidence[ClassManifest[T]].newArrayN(len)
- val Some((level, manifType)) = erasure.GenericArray.unapply(tpt.tpe)
- if (level > MaxArrayDims)
- MultiDimensionalArrayError(tree)
- else {
+ // convert new Array[T](len) to evidence[ClassTag[T]].newArray(len)
+ // convert new Array^N[T](len) for N > 1 to evidence[ClassTag[Array[...Array[T]...]]].newArray(len), where Array HK gets applied (N-1) times
+ // [Eugene] no more MaxArrayDims. ClassTags are flexible enough to allow creation of arrays of arbitrary dimensionality (w.r.t JVM restrictions)
+ val Some((level, componentType)) = erasure.GenericArray.unapply(tpt.tpe)
+ val tagType = List.iterate(componentType, level)(tpe => appliedType(ArrayClass.asType, List(tpe))).last
val newArrayApp = atPos(tree.pos) {
- val manif = getManifestTree(tree, manifType, false)
- new ApplyToImplicitArgs(Select(manif, if (level == 1) "newArray" else "newArray"+level), args)
+ val tag = resolveClassTag(tree, tagType)
+ if (tag.isEmpty) MissingClassTagError(tree, tagType)
+ else new ApplyToImplicitArgs(Select(tag, nme.newArray), args)
}
typed(newArrayApp, mode, pt)
- }
case tree1 =>
tree1
}
@@ -4725,7 +4768,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case ReferenceToBoxed(idt @ Ident(_)) =>
val id1 = typed1(idt, mode, pt) match { case id: Ident => id }
- treeCopy.ReferenceToBoxed(tree, id1) setType AnyRefClass.tpe
+ // [Eugene] am I doing it right?
+ val erasedTypes = phaseId(currentPeriod) >= currentRun.erasurePhase.id
+ val tpe = capturedVariableType(idt.symbol, erasedTypes = erasedTypes)
+ treeCopy.ReferenceToBoxed(tree, id1) setType tpe
case Literal(value) =>
tree setType (
@@ -4964,6 +5010,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def typedTypeConstructor(tree: Tree): Tree = typedTypeConstructor(tree, NOmode)
def computeType(tree: Tree, pt: Type): Type = {
+ // macros employ different logic of `computeType`
+ assert(!context.owner.isTermMacro, context.owner)
val tree1 = typed(tree, pt)
transformed(tree) = tree1
val tpe = packedType(tree1, context.owner)
@@ -4971,26 +5019,68 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
tpe
}
+ def computeMacroDefType(tree: Tree, pt: Type): Type = {
+ assert(context.owner.isTermMacro, context.owner)
+ assert(tree.symbol.isTermMacro, tree.symbol)
+ assert(tree.isInstanceOf[DefDef], tree.getClass)
+ val ddef = tree.asInstanceOf[DefDef]
+
+ val tree1 =
+ if (transformed contains ddef.rhs) {
+ // macro defs are typechecked in `methodSig` (by calling this method) in order to establish their link to macro implementation asap
+ // if a macro def doesn't have explicitly specified return type, this method will be called again by `assignTypeToTree`
+ // here we guard against this case
+ transformed(ddef.rhs)
+ } else {
+ val tree1 = typedMacroBody(this, ddef)
+ transformed(ddef.rhs) = tree1
+ tree1
+ }
+
+ val isMacroBodyOkay = !tree.symbol.isErroneous && !(tree1 exists (_.isErroneous))
+ if (isMacroBodyOkay) computeMacroDefTypeFromMacroImpl(ddef, tree.symbol, tree1.symbol) else AnyClass.tpe
+ }
+
+ def transformedOr(tree: Tree, op: => Tree): Tree = transformed.get(tree) match {
+ case Some(tree1) => transformed -= tree; tree1
+ case None => op
+ }
+
def transformedOrTyped(tree: Tree, mode: Int, pt: Type): Tree = transformed.get(tree) match {
case Some(tree1) => transformed -= tree; tree1
case None => typed(tree, mode, pt)
}
- def findManifest(tp: Type, full: Boolean) = beforeTyper {
+ // `tree` is only necessary here for its position
+ // but that's invaluable for error reporting, so I decided to include it into this method's contract
+ // before passing EmptyTree, please, consider passing something meaningful first
+ def resolveClassTag(tree: Tree, tp: Type): Tree = beforeTyper {
inferImplicit(
EmptyTree,
- appliedType((if (full) FullManifestClass else PartialManifestClass).typeConstructor, List(tp)),
- true, false, context)
+ appliedType(ClassTagClass.typeConstructor, List(tp)),
+ /*reportAmbiguous =*/ true,
+ /*isView =*/ false,
+ /*context =*/ context,
+ /*saveAmbiguousDivergent =*/ true,
+ /*pos =*/ tree.pos
+ ).tree
}
- def getManifestTree(tree: Tree, tp: Type, full: Boolean): Tree = {
- val manifestOpt = findManifest(tp, full)
- if (manifestOpt.tree.isEmpty) {
- MissingManifestError(tree, full, tp)
- } else {
- manifestOpt.tree
- }
+ // `tree` is only necessary here for its position
+ // but that's invaluable for error reporting, so I decided to include it into this method's contract
+ // before passing EmptyTree, please, consider passing something meaningful first
+ def resolveTypeTag(tree: Tree, pre: Type, tp: Type, full: Boolean): Tree = beforeTyper {
+ inferImplicit(
+ EmptyTree,
+ appliedType(singleType(pre, pre member (if (full) ConcreteTypeTagClass else TypeTagClass).name), List(tp)),
+ /*reportAmbiguous =*/ true,
+ /*isView =*/ false,
+ /*context =*/ context,
+ /*saveAmbiguousDivergent =*/ true,
+ /*pos =*/ tree.pos
+ ).tree
}
+
/*
def convertToTypeTree(tree: Tree): Tree = tree match {
case TypeTree() => tree
diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
index 4f5b6868ae..1f79d8212d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
@@ -112,8 +112,8 @@ trait Unapplies extends ast.TreeDSL
private def toIdent(x: DefTree) = Ident(x.name) setPos x.pos.focus
- private def classType(cdef: ClassDef, tparams: List[TypeDef]): Tree = {
- val tycon = REF(cdef.symbol)
+ private def classType(cdef: ClassDef, tparams: List[TypeDef], symbolic: Boolean = true): Tree = {
+ val tycon = if (symbolic) REF(cdef.symbol) else Ident(cdef.name)
if (tparams.isEmpty) tycon else AppliedTypeTree(tycon, tparams map toIdent)
}
@@ -166,15 +166,20 @@ trait Unapplies extends ast.TreeDSL
/** The apply method corresponding to a case class
*/
- def caseModuleApplyMeth(cdef: ClassDef): DefDef = {
+ def factoryMeth(mods: Modifiers, name: TermName, cdef: ClassDef, symbolic: Boolean): DefDef = {
val tparams = cdef.tparams map copyUntypedInvariant
val cparamss = constrParamss(cdef)
+ def classtpe = classType(cdef, tparams, symbolic)
atPos(cdef.pos.focus)(
- DefDef(caseMods, nme.apply, tparams, cparamss, classType(cdef, tparams),
- New(classType(cdef, tparams), mmap(cparamss)(gen.paramToArg)))
+ DefDef(mods, name, tparams, cparamss, classtpe,
+ New(classtpe, mmap(cparamss)(gen.paramToArg)))
)
}
+ /** The apply method corresponding to a case class
+ */
+ def caseModuleApplyMeth(cdef: ClassDef): DefDef = factoryMeth(caseMods, nme.apply, cdef, symbolic = true)
+
/** The unapply method corresponding to a case class
*/
def caseModuleUnapplyMeth(cdef: ClassDef): DefDef = {
diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala
index ce10ee34a2..11d7db5180 100644
--- a/src/compiler/scala/tools/nsc/util/ClassPath.scala
+++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala
@@ -27,7 +27,7 @@ object ClassPath {
def scalaCompiler = locate[Global]
def infoFor[T](value: T) = info(value.getClass)
- def info[T](clazz: Class[T]) = new ClassAndJarInfo()(ClassManifest fromClass clazz)
+ def info[T](clazz: Class[T]) = new ClassAndJarInfo()(ClassManifest[T](clazz))
def info[T: ClassManifest] = new ClassAndJarInfo[T]
def locate[T: ClassManifest] = info[T] rootClasspath
def locateJar[T: ClassManifest] = info[T].rootPossibles find (x => isJarOrZip(x)) map (x => File(x))
diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala
index bc74717366..573f7bc7b2 100644
--- a/src/compiler/scala/tools/nsc/util/Position.scala
+++ b/src/compiler/scala/tools/nsc/util/Position.scala
@@ -33,62 +33,24 @@ object Position {
}
}
-/**
- * A tree does not directly store a Position. It stores a TreeAnnotation, which /typically/ is a Position.
- *
- * A TreeAnnotion may encompass more than just a Position, though, depending on the exact subclass of TreeAnnotation.
- */
-trait TreeAnnotation {
- def pos: Position
-}
+trait Position extends scala.reflect.api.Position with scala.reflect.api.Attachment {
+ /** Exposes itself as payload of Attachment */
+ // necessary for conformance with Attachment
+ def pos: Position = this
+ /** A bit weird method that is necessary to safely update positions without destroying custom attachments */
+ // necessary for conformance with Attachment
+ def withPos(pos: scala.reflect.api.Position) = pos
-/** The Position class and its subclasses represent positions of ASTs and symbols.
- * Except for NoPosition and FakePos, every position refers to a SourceFile
- * and to an offset in the sourcefile (its `point`). For batch compilation,
- * that's all. For interactive IDE's there are also RangePositions
- * and TransparentPositions. A RangePosition indicates a start and an end
- * in addition to its point. TransparentPositions are a subclass of RangePositions.
- * Range positions that are not transparent are called opaque.
- * Trees with RangePositions need to satisfy the following invariants.
- *
- * INV1: A tree with an offset position never contains a child
- * with a range position
- * INV2: If the child of a tree with a range position also has a range position,
- * then the child's range is contained in the parent's range.
- * INV3: Opaque range positions of children of the same node are non-overlapping
- * (this means their overlap is at most a single point).
- *
- * The following tests are useful on positions:
- *
- * pos.isDefined true if position is not a NoPosition nor a FakePosition
- * pos.isRange true if position is a range
- * pos.isOpaqueRange true if position is an opaque range
- *
- * The following accessor methods are provided:
- *
- * pos.source The source file of the position, which must be defined
- * pos.point The offset of the position's point, which must be defined
- * pos.start The start of the position, which must be a range
- * pos.end The end of the position, which must be a range
- *
- * There are also convenience methods, such as
- *
- * pos.startOrPoint
- * pos.endOrPoint
- * pos.pointOrElse(default)
- *
- * These are less strict about the kind of position on which they can be applied.
- *
- * The following conversion methods are often used:
- *
- * pos.focus converts a range position to an offset position, keeping its point;
- * returns all other positions unchanged.
- * pos.makeTransparent converts an opaque range position into a transparent one.
- * returns all other positions unchanged.
- */
-trait Position extends TreeAnnotation {
- def pos: Position = this
+ /** Java file corresponding to the source file of this position.
+ */
+ // necessary for conformance with scala.reflect.api.Position
+ def fileInfo: java.io.File = source.file.file
+
+ /** Contents of the source file that contains this position.
+ */
+ // necessary for conformance with scala.reflect.api.Position
+ def fileContent: Array[Char] = source.content
/** An optional value containing the source file referred to by this position, or
* None if not defined.
@@ -134,74 +96,74 @@ trait Position extends TreeAnnotation {
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) = this
+ def withStart(off: Int): Position = this
/** The same position with a different end value (if a range) */
- def withEnd(off: Int) = this
+ def withEnd(off: Int): Position = this
/** The same position with a different point value (if a range or offset) */
- def withPoint(off: Int) = this
+ 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) = this
+ 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) = this
+ def union(pos: scala.reflect.api.Position): Position = this
/** If this is a range position, the offset position of its start.
* Otherwise the position itself
*/
- def focusStart = this
+ def focusStart: Position = this
/** If this is a range position, the offset position of its point.
* Otherwise the position itself
*/
- def focus = this
+ def focus: Position = this
/** If this is a range position, the offset position of its end.
* Otherwise the position itself
*/
- def focusEnd = this
+ def focusEnd: Position = this
/** Does this position include the given position `pos`.
* This holds if `this` is a range position and its range [start..end]
* is the same or covers the range of the given position, which may or may not be a range position.
*/
- def includes(pos: Position) = false
+ def includes(pos: scala.reflect.api.Position): Boolean = false
/** Does this position properly include the given position `pos` ("properly" meaning their
* ranges are not the same)?
*/
- def properlyIncludes(pos: Position) =
+ def properlyIncludes(pos: scala.reflect.api.Position): Boolean =
includes(pos) && (start < pos.startOrPoint || pos.endOrPoint < end)
/** Does this position precede that position?
* This holds if both positions are defined and the end point of this position
* is not larger than the start point of the given position.
*/
- def precedes(pos: Position) =
+ def precedes(pos: scala.reflect.api.Position): Boolean =
isDefined && pos.isDefined && endOrPoint <= pos.startOrPoint
/** Does this position properly precede the given position `pos` ("properly" meaning their ranges
* do not share a common point).
*/
- def properlyPrecedes(pos: Position) =
+ def properlyPrecedes(pos: scala.reflect.api.Position): Boolean =
isDefined && pos.isDefined && endOrPoint < pos.startOrPoint
/** Does this position overlap with that position?
* This holds if both positions are ranges and there is an interval of
* non-zero length that is shared by both position ranges.
*/
- def overlaps(pos: Position) =
+ def overlaps(pos: scala.reflect.api.Position): Boolean =
isRange && pos.isRange &&
((pos.start < end && start < pos.end) || (start < pos.end && pos.start < end))
/** Does this position cover the same range as that position?
* Holds only if both position are ranges
*/
- def sameRange(pos: Position) =
+ def sameRange(pos: scala.reflect.api.Position): Boolean =
isRange && pos.isRange && start == pos.start && end == pos.end
def line: Int = throw new UnsupportedOperationException("Position.line")
@@ -219,11 +181,11 @@ trait Position extends TreeAnnotation {
* file. If the SourceFile is a normal SourceFile, simply
* return this.
*/
- def inUltimateSource(source : SourceFile) =
+ def inUltimateSource(source : SourceFile): Position =
if (source == null) this else source.positionInUltimateSource(this)
- def dbgString = toString
- def safeLine = try line catch { case _: UnsupportedOperationException => -1 }
+ def dbgString: String = toString
+ def safeLine: Int = try line catch { case _: UnsupportedOperationException => -1 }
def show: String = "["+toString+"]"
}
@@ -254,8 +216,10 @@ class OffsetPosition(override val source: SourceFile, override val point: Int) e
col + 1
}
- override def union(pos: Position) =
- if (pos.isRange) pos else this
+ override def union(pos: scala.reflect.api.Position) =
+ // [Eugene] how do I get rid of this cast?
+ // I could introduce a "type PositionType <: scala.reflect.api.Position", but that's also ugly
+ if (pos.isRange) pos.asInstanceOf[Position] else this
override def equals(that : Any) = that match {
case that : OffsetPosition => point == that.point && source.file == that.source.file
@@ -265,7 +229,7 @@ class OffsetPosition(override val source: SourceFile, override val point: Int) e
override def toString = {
val pointmsg = if (point > source.length) "out-of-bounds-" else "offset="
- "source-%s,line-%s,%s%s".format(source.path, line, pointmsg, point)
+ "source-%s,line-%s,%s%s".format(source.file.canonicalPath, line, pointmsg, point)
}
override def show = "["+point+"]"
}
@@ -289,8 +253,8 @@ extends OffsetPosition(source, point) {
}
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) =
+ override def includes(pos: scala.reflect.api.Position) = pos.isDefined && start <= pos.startOrPoint && pos.endOrPoint <= end
+ override def union(pos: scala.reflect.api.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 {
@@ -301,7 +265,7 @@ extends OffsetPosition(source, point) {
case _ => this
}
- override def toString = "RangePosition("+source+", "+start+", "+point+", "+end+")"
+ override def toString = "RangePosition("+source.file.canonicalPath+", "+start+", "+point+", "+end+")"
override def show = "["+start+":"+end+"]"
private var focusCache: Position = NoPosition
}
@@ -311,10 +275,4 @@ class TransparentPosition(source: SourceFile, start: Int, point: Int, end: Int)
override def isTransparent = true
override def makeTransparent = this
override def show = "<"+start+":"+end+">"
-}
-
-
-
-
-
-
+} \ No newline at end of file
diff --git a/src/compiler/scala/tools/reflect/package.scala b/src/compiler/scala/tools/reflect/package.scala
index 8f5e099fbf..f5c836a4e9 100644
--- a/src/compiler/scala/tools/reflect/package.scala
+++ b/src/compiler/scala/tools/reflect/package.scala
@@ -27,7 +27,7 @@ package object reflect {
}
}
- def zeroOfClass(clazz: Class[_]) = zeroOf(Manifest.classType(clazz))
+ def zeroOfClass(clazz: Class[_]) = zeroOf(Manifest(ClassManifest(clazz).tpe))
def zeroOf[T](implicit m: Manifest[T]): AnyRef = {
if (m == manifest[Boolean] || m == manifest[jl.Boolean]) false: jl.Boolean
else if (m == manifest[Unit] || m == manifest[jl.Void] || m == manifest[scala.runtime.BoxedUnit]) scala.runtime.BoxedUnit.UNIT