summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAleksandar Prokopec <axel22@gmail.com>2012-02-06 09:13:55 +0100
committerAleksandar Prokopec <axel22@gmail.com>2012-02-06 09:13:55 +0100
commit1b2eea91de3511e41fef77e667681cc474790248 (patch)
treecb956a3b5ac6a19e52455dbe086a713ad1f27be9 /src
parenta015c08fda8b8556345a802d60557a3ecd627ccc (diff)
parent28b2d0c13aba7156431076119c920c7dcee6dc77 (diff)
downloadscala-1b2eea91de3511e41fef77e667681cc474790248.tar.gz
scala-1b2eea91de3511e41fef77e667681cc474790248.tar.bz2
scala-1b2eea91de3511e41fef77e667681cc474790248.zip
Merge branch 'master' into feature/pc-ctrie
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/reflect/internal/Constants.scala2
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala6
-rw-r--r--src/compiler/scala/reflect/internal/Flags.scala44
-rw-r--r--src/compiler/scala/reflect/internal/Importers.scala32
-rw-r--r--src/compiler/scala/reflect/internal/Names.scala7
-rw-r--r--src/compiler/scala/reflect/internal/StdNames.scala11
-rw-r--r--src/compiler/scala/reflect/internal/Symbols.scala37
-rw-r--r--src/compiler/scala/reflect/internal/Trees.scala17
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala3
-rw-r--r--src/compiler/scala/reflect/runtime/JavaToScala.scala118
-rw-r--r--src/compiler/scala/reflect/runtime/Mirror.scala14
-rw-r--r--src/compiler/scala/reflect/runtime/ToolBoxes.scala49
-rw-r--r--src/compiler/scala/reflect/runtime/TreeBuildUtil.scala3
-rw-r--r--src/compiler/scala/tools/ant/Scalac.scala2
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala16
-rw-r--r--src/compiler/scala/tools/nsc/ast/Reifiers.scala (renamed from src/compiler/scala/tools/nsc/transform/LiftCode.scala)264
-rw-r--r--src/compiler/scala/tools/nsc/ast/ReifyPrinters.scala75
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala107
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Scanners.scala10
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala11
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Members.scala3
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala100
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala37
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IMain.scala6
-rw-r--r--src/compiler/scala/tools/nsc/io/Path.scala2
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala44
-rw-r--r--src/compiler/scala/tools/nsc/transform/Flatten.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala12
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala13
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala1307
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala33
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java10
-rw-r--r--src/intellij/scala-lang.ipr.SAMPLE3
-rw-r--r--src/intellij/scala.iml.SAMPLE10
-rw-r--r--src/library/scala/MatchingStrategy.scala27
-rwxr-xr-xsrc/library/scala/collection/IndexedSeqOptimized.scala2
-rw-r--r--src/library/scala/math/BigDecimal.scala4
-rw-r--r--src/library/scala/reflect/Code.scala2
-rw-r--r--src/library/scala/reflect/Manifest.scala2
-rw-r--r--src/library/scala/reflect/api/Mirror.scala32
-rw-r--r--src/library/scala/reflect/api/Modifier.scala83
-rwxr-xr-xsrc/library/scala/reflect/api/Names.scala13
-rwxr-xr-xsrc/library/scala/reflect/api/StandardDefinitions.scala22
-rw-r--r--src/library/scala/reflect/api/StandardNames.scala21
-rwxr-xr-xsrc/library/scala/reflect/api/Symbols.scala103
-rw-r--r--src/library/scala/reflect/api/TreeBuildUtil.scala14
-rw-r--r--src/library/scala/reflect/api/TreePrinters.scala16
-rw-r--r--src/library/scala/reflect/api/Trees.scala30
-rwxr-xr-xsrc/library/scala/reflect/api/Types.scala22
-rwxr-xr-xsrc/library/scala/reflect/api/Universe.scala3
-rw-r--r--src/library/scala/reflect/macro/Context.scala21
-rw-r--r--src/partest/scala/tools/partest/PartestTask.scala12
-rw-r--r--src/partest/scala/tools/partest/nest/CompileManager.scala2
-rw-r--r--src/partest/scala/tools/partest/nest/PathSettings.scala7
-rw-r--r--src/partest/scala/tools/partest/nest/ReflectiveRunner.scala8
-rw-r--r--src/partest/scala/tools/partest/nest/TestFile.scala4
-rw-r--r--src/partest/scala/tools/partest/nest/Worker.scala4
-rw-r--r--src/partest/scala/tools/partest/utils/CodeTest.scala35
-rw-r--r--src/scalap/scala/tools/scalap/Classfiles.scala26
63 files changed, 1623 insertions, 1319 deletions
diff --git a/src/compiler/scala/reflect/internal/Constants.scala b/src/compiler/scala/reflect/internal/Constants.scala
index 9c4b2b2245..c328cc49cb 100644
--- a/src/compiler/scala/reflect/internal/Constants.scala
+++ b/src/compiler/scala/reflect/internal/Constants.scala
@@ -45,7 +45,7 @@ trait Constants extends api.Constants {
case x: Char => CharTag
case x: Type => ClassTag
case x: Symbol => EnumTag
- case _ => throw new Error("bad constant value: " + value)
+ case _ => throw new Error("bad constant value: " + value + " of class " + value.getClass)
}
def isByteRange: Boolean = isIntRange && Byte.MinValue <= intValue && intValue <= Byte.MaxValue
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala
index 8114be20d5..e05ac1087b 100644
--- a/src/compiler/scala/reflect/internal/Definitions.scala
+++ b/src/compiler/scala/reflect/internal/Definitions.scala
@@ -402,9 +402,6 @@ trait Definitions extends reflect.api.StandardDefinitions {
lazy val FullManifestModule = getRequiredModule("scala.reflect.Manifest")
lazy val OptManifestClass = getRequiredClass("scala.reflect.OptManifest")
lazy val NoManifest = getRequiredModule("scala.reflect.NoManifest")
- lazy val CodeClass = getClass(sn.Code)
- lazy val CodeModule = getModule(sn.Code)
- lazy val Code_lift = getMember(CodeModule, nme.lift_)
lazy val ScalaSignatureAnnotation = getRequiredClass("scala.reflect.ScalaSignature")
lazy val ScalaLongSignatureAnnotation = getRequiredClass("scala.reflect.ScalaLongSignature")
@@ -608,6 +605,9 @@ trait Definitions extends reflect.api.StandardDefinitions {
def ClassType(arg: Type) =
if (phase.erasedTypes || forMSIL) ClassClass.tpe
else appliedType(ClassClass.typeConstructor, List(arg))
+
+ def vmClassType(arg: Type): Type = ClassType(arg)
+ def vmSignature(sym: Symbol, info: Type): String = signature(info) // !!!
//
// .NET backend
diff --git a/src/compiler/scala/reflect/internal/Flags.scala b/src/compiler/scala/reflect/internal/Flags.scala
index 9e4f0431c3..aa696bc6e8 100644
--- a/src/compiler/scala/reflect/internal/Flags.scala
+++ b/src/compiler/scala/reflect/internal/Flags.scala
@@ -13,7 +13,7 @@ import scala.collection.{ mutable, immutable }
// Parsers/JavaParsers and therefore definitely appear on Modifiers; but the
// absence of /M on the other flags does not imply they aren't.
//
-// Generated by mkFlagsTable() at Mon Oct 11 10:01:09 PDT 2010
+// Generated by mkFlagsTable() at Thu Feb 02 20:31:52 PST 2012
//
// 0: PROTECTED/M
// 1: OVERRIDE/M
@@ -30,7 +30,7 @@ import scala.collection.{ mutable, immutable }
// 12: MUTABLE/M
// 13: PARAM/M
// 14: PACKAGE
-// 15:
+// 15: MACRO/M
// 16: BYNAMEPARAM/M CAPTURED COVARIANT/M
// 17: CONTRAVARIANT/M INCONSTRUCTOR LABEL
// 18: ABSOVERRIDE/M
@@ -59,13 +59,13 @@ import scala.collection.{ mutable, immutable }
// 41: DEFAULTINIT/M
// 42: VBRIDGE
// 43: VARARGS
-// 44:
+// 44: TRIEDCOOKING
// 45:
// 46:
// 47:
// 48:
-// 49: latePRIVATE (eliminated)
-// 50: lateABSTRACT (eliminated)
+// 49:
+// 50:
// 51: lateDEFERRED
// 52: lateFINAL
// 53: lateMETHOD
@@ -74,10 +74,10 @@ import scala.collection.{ mutable, immutable }
// 56: notPROTECTED
// 57: notOVERRIDE
// 58: notPRIVATE
-// 59: notABSTRACT (eliminated)
-// 60: notDEFERRED (eliminated)
-// 61: notFINAL (eliminated)
-// 62: notMETHOD (eliminated)
+// 59:
+// 60:
+// 61:
+// 62:
// 63:
/** Flags set on Modifiers instances in the parsing stage.
@@ -337,7 +337,7 @@ class Flags extends ModifierFlags {
// ------ displaying flags --------------------------------------------------------
- // Generated by mkFlagToStringMethod() at Mon Oct 11 10:12:36 PDT 2010
+ // Generated by mkFlagToStringMethod() at Thu Feb 02 20:31:52 PST 2012
@annotation.switch override def flagToString(flag: Long): String = flag match {
case PROTECTED => "protected" // (1L << 0)
case OVERRIDE => "override" // (1L << 1)
@@ -354,7 +354,7 @@ class Flags extends ModifierFlags {
case MUTABLE => "<mutable>" // (1L << 12)
case PARAM => "<param>" // (1L << 13)
case PACKAGE => "<package>" // (1L << 14)
- case MACRO => "macro" // (1L << 15)
+ case MACRO => "<macro>" // (1L << 15)
case BYNAMEPARAM => "<bynameparam/captured/covariant>" // (1L << 16)
case CONTRAVARIANT => "<contravariant/inconstructor/label>" // (1L << 17)
case ABSOVERRIDE => "absoverride" // (1L << 18)
@@ -383,13 +383,13 @@ class Flags extends ModifierFlags {
case DEFAULTINIT => "<defaultinit>" // (1L << 41)
case VBRIDGE => "<vbridge>" // (1L << 42)
case VARARGS => "<varargs>" // (1L << 43)
- case 0x100000000000L => "" // (1L << 44)
+ case TRIEDCOOKING => "<triedcooking>" // (1L << 44)
case 0x200000000000L => "" // (1L << 45)
case 0x400000000000L => "" // (1L << 46)
case 0x800000000000L => "" // (1L << 47)
case 0x1000000000000L => "" // (1L << 48)
- // case `latePRIVATE` => "<lateprivate>" // (1L << 49)
- // case `lateABSTRACT` => "<lateabstract>" // (1L << 50)
+ case 0x2000000000000L => "" // (1L << 49)
+ case 0x4000000000000L => "" // (1L << 50)
case `lateDEFERRED` => "<latedeferred>" // (1L << 51)
case `lateFINAL` => "<latefinal>" // (1L << 52)
case `lateMETHOD` => "<latemethod>" // (1L << 53)
@@ -398,10 +398,10 @@ class Flags extends ModifierFlags {
case `notPROTECTED` => "<notprotected>" // (1L << 56)
case `notOVERRIDE` => "<notoverride>" // (1L << 57)
case `notPRIVATE` => "<notprivate>" // (1L << 58)
- // case `notABSTRACT` => "<notabstract>" // (1L << 59)
- // case `notDEFERRED` => "<notdeferred>" // (1L << 60)
- // case `notFINAL` => "<notfinal>" // (1L << 61)
- // case `notMETHOD` => "<notmethod>" // (1L << 62)
+ case 0x800000000000000L => "" // (1L << 59)
+ case 0x1000000000000000L => "" // (1L << 60)
+ case 0x2000000000000000L => "" // (1L << 61)
+ case 0x4000000000000000L => "" // (1L << 62)
case 0x8000000000000000L => "" // (1L << 63)
case _ => ""
}
@@ -466,7 +466,7 @@ class Flags extends ModifierFlags {
}
protected final val rawFlagPickledOrder: Array[Long] = pickledListOrder.toArray
- def flagOfModifier(mod: Modifier.Value): Long = mod match {
+ def flagOfModifier(mod: Modifier): Long = mod match {
case Modifier.`protected` => PROTECTED
case Modifier.`private` => PRIVATE
case Modifier.`override` => OVERRIDE
@@ -496,13 +496,13 @@ class Flags extends ModifierFlags {
case Modifier.bynameParameter => BYNAMEPARAM
}
- def flagsOfModifiers(mods: List[Modifier.Value]): Long =
+ def flagsOfModifiers(mods: List[Modifier]): Long =
(mods :\ 0L) { (mod, curr) => curr | flagOfModifier(mod) }
- def modifierOfFlag(flag: Long): Option[Modifier.Value] =
+ def modifierOfFlag(flag: Long): Option[Modifier] =
Modifier.values find { mod => flagOfModifier(mod) == flag }
- def modifiersOfFlags(flags: Long): List[Modifier.Value] =
+ def modifiersOfFlags(flags: Long): List[Modifier] =
pickledListOrder map (mask => modifierOfFlag(flags & mask)) flatMap { mod => mod }
}
diff --git a/src/compiler/scala/reflect/internal/Importers.scala b/src/compiler/scala/reflect/internal/Importers.scala
index 23b443919a..6c843e6f15 100644
--- a/src/compiler/scala/reflect/internal/Importers.scala
+++ b/src/compiler/scala/reflect/internal/Importers.scala
@@ -145,8 +145,8 @@ trait Importers { self: SymbolTable =>
PolyType(tparams map importSymbol, importType(restpe))
case from.NullaryMethodType(restpe) =>
NullaryMethodType(importType(restpe))
- case from.ConstantType(from.Constant(value)) =>
- ConstantType(Constant(value))
+ case from.ConstantType(constant @ from.Constant(_)) =>
+ ConstantType(importConstant(constant))
case from.SuperType(thistpe, supertpe) =>
SuperType(importType(thistpe), importType(supertpe))
case from.TypeBounds(lo, hi) =>
@@ -194,8 +194,8 @@ trait Importers { self: SymbolTable =>
})
def importAnnotArg(arg: from.ClassfileAnnotArg): ClassfileAnnotArg = arg match {
- case from.LiteralAnnotArg(from.Constant(value)) =>
- LiteralAnnotArg(Constant(value))
+ case from.LiteralAnnotArg(constant @ from.Constant(_)) =>
+ LiteralAnnotArg(importConstant(constant))
case from.ArrayAnnotArg(args) =>
ArrayAnnotArg(args map importAnnotArg)
case from.ScalaSigBytes(bytes) =>
@@ -303,8 +303,8 @@ trait Importers { self: SymbolTable =>
case _ =>
new Ident(importName(name))
}
- case from.Literal(from.Constant(value)) =>
- new Literal(Constant(value))
+ case from.Literal(constant @ from.Constant(_)) =>
+ new Literal(importConstant(constant))
case from.TypeTree() =>
new TypeTree()
case from.Annotated(annot, arg) =>
@@ -327,8 +327,19 @@ trait Importers { self: SymbolTable =>
null
}
if (mytree != null) {
- if (mytree hasSymbol) mytree.symbol = importSymbol(tree.symbol)
- mytree.tpe = importType(tree.tpe)
+ val mysym = if (tree hasSymbol) importSymbol(tree.symbol) else NoSymbol
+ val mytpe = importType(tree.tpe)
+
+ mytree match {
+ case mytt: TypeTree =>
+ val tt = tree.asInstanceOf[from.TypeTree]
+ if (mytree hasSymbol) mytt.symbol = mysym
+ if (tt.wasEmpty) mytt.defineType(mytpe) else mytt.setType(mytpe)
+ if (tt.original != null) mytt.setOriginal(importTree(tt.original))
+ case _ =>
+ if (mytree hasSymbol) mytree.symbol = importSymbol(tree.symbol)
+ mytree.tpe = importType(tree.tpe)
+ }
}
mytree
}
@@ -339,5 +350,10 @@ trait Importers { self: SymbolTable =>
def importRefTree(tree: from.RefTree): RefTree = importTree(tree).asInstanceOf[RefTree]
def importIdent(tree: from.Ident): Ident = importTree(tree).asInstanceOf[Ident]
def importCaseDef(tree: from.CaseDef): CaseDef = importTree(tree).asInstanceOf[CaseDef]
+ def importConstant(constant: from.Constant): Constant = new Constant(constant.tag match {
+ case ClassTag => 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/Names.scala b/src/compiler/scala/reflect/internal/Names.scala
index 907b564d4c..e6ca4c49ba 100644
--- a/src/compiler/scala/reflect/internal/Names.scala
+++ b/src/compiler/scala/reflect/internal/Names.scala
@@ -387,6 +387,13 @@ trait Names extends api.Names {
* decode returns a String.
*/
+ /** !!! Duplicative but consistently named.
+ */
+ def decoded: String = decode
+ def encoded: String = "" + encode
+ // def decodedName: ThisNameType = newName(decoded)
+ def encodedName: ThisNameType = encode
+
/** Replace operator symbols by corresponding $op_name. */
def encode: ThisNameType = {
val str = toString
diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala
index b3069adfb4..a072a2eebe 100644
--- a/src/compiler/scala/reflect/internal/StdNames.scala
+++ b/src/compiler/scala/reflect/internal/StdNames.scala
@@ -272,6 +272,8 @@ trait StdNames extends NameManglers { self: SymbolTable =>
// val productElementName: NameType = "productElementName"
val Ident: NameType = "Ident"
val StringContext: NameType = "StringContext"
+ val This: NameType = "This"
+ val Tree : NameType = "Tree"
val TYPE_ : NameType = "TYPE"
val TypeTree: NameType = "TypeTree"
val UNIT : NameType = "UNIT"
@@ -368,7 +370,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val self: NameType = "self"
val setAccessible: NameType = "setAccessible"
val setAnnotations: NameType = "setAnnotations"
- val setTypeSig: NameType = "setTypeSig"
+ val setTypeSignature: NameType = "setTypeSignature"
val synchronized_ : NameType = "synchronized"
val tail: NameType = "tail"
val thisModuleType: NameType = "thisModuleType"
@@ -426,7 +428,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val toInteger: NameType = "toInteger"
}
- object tpnme extends TypeNames /*with LibraryTypeNames*/ with TypeNameMangling {
+ object tpnme extends AbsTypeNames with TypeNames /*with LibraryTypeNames*/ with TypeNameMangling {
type NameType = TypeName
protected implicit def createNameType(name: String): TypeName = newTypeNameCached(name)
@@ -463,7 +465,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val javanme = nme.javaKeywords
- object nme extends TermNames /*with LibraryTermNames*/ with TermNameMangling {
+ object nme extends AbsTermNames with TermNames /*with LibraryTermNames*/ with TermNameMangling {
type NameType = TermName
protected implicit def createNameType(name: String): TermName = newTermNameCached(name)
@@ -710,7 +712,6 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val BoxedCharacter : TypeName
val BoxedNumber : TypeName
val Class : TypeName
- val Code : TypeName
val Delegate : TypeName
val IOOBException : TypeName // IndexOutOfBoundsException
val InvTargetException : TypeName // InvocationTargetException
@@ -845,7 +846,6 @@ trait StdNames extends NameManglers { self: SymbolTable =>
final val BoxedCharacter: TypeName = "System.IConvertible"
final val BoxedNumber: TypeName = "System.IConvertible"
final val Class: TypeName = "System.Type"
- final val Code: TypeName = tpnme.NO_NAME
final val Delegate: TypeName = "System.MulticastDelegate"
final val IOOBException: TypeName = "System.IndexOutOfRangeException"
final val InvTargetException: TypeName = "System.Reflection.TargetInvocationException"
@@ -879,7 +879,6 @@ trait StdNames extends NameManglers { self: SymbolTable =>
private class J2SENames extends JavaNames {
final val BeanProperty: TypeName = "scala.beans.BeanProperty"
final val BooleanBeanProperty: TypeName = "scala.beans.BooleanBeanProperty"
- final val Code: TypeName = "scala.reflect.Code"
final val JavaSerializable: TypeName = "java.io.Serializable"
}
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala
index 94d764067f..819d94f41a 100644
--- a/src/compiler/scala/reflect/internal/Symbols.scala
+++ b/src/compiler/scala/reflect/internal/Symbols.scala
@@ -61,13 +61,18 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
case n: TermName => newTermSymbol(n, pos, newFlags)
case n: TypeName => newTypeSymbol(n, pos, newFlags)
}
- def typeSig: Type = info
- def typeSigIn(site: Type): Type = site.memberInfo(this)
+ def enclosingClass: Symbol = enclClass
+ def enclosingMethod: Symbol = enclMethod
+ def thisPrefix: Type = thisType
+ def selfType: Type = typeOfThis
+ def typeSignature: Type = info
+ def typeSignatureIn(site: Type): Type = site memberInfo this
+
def asType: Type = tpe
def asTypeIn(site: Type): Type = site.memberType(this)
def asTypeConstructor: Type = typeConstructor
def setInternalFlags(flag: Long): this.type = { setFlag(flag); this }
- def setTypeSig(tpe: Type): this.type = { setInfo(tpe); this }
+ def setTypeSignature(tpe: Type): this.type = { setInfo(tpe); this }
def setAnnotations(annots: AnnotationInfo*): this.type = { setAnnotations(annots.toList); this }
}
@@ -103,12 +108,17 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def pos = rawpos
def setPos(pos: Position): this.type = { this.rawpos = pos; this }
- override def hasModifier(mod: Modifier.Value) =
+ /** !!! The logic after "hasFlag" is far too opaque to be unexplained.
+ * I'm guessing it's attempting to compensate for flag overloading,
+ * and embedding such logic in an undocumented island like this is a
+ * notarized guarantee of future breakage.
+ */
+ override def hasModifier(mod: Modifier) =
hasFlag(flagOfModifier(mod)) &&
(!(mod == Modifier.bynameParameter) || isTerm) &&
(!(mod == Modifier.covariant) || isType)
- override def allModifiers: Set[Modifier.Value] =
+ override def modifiers: Set[Modifier] =
Modifier.values filter hasModifier
// ------ creators -------------------------------------------------------------------
@@ -1271,7 +1281,14 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** After the typer phase (before, look at the definition's Modifiers), contains
* the annotations attached to member a definition (class, method, type, field).
*/
- def annotations: List[AnnotationInfo] = _annotations
+ def annotations: List[AnnotationInfo] = {
+ // Necessary for reflection, see SI-5423
+ if (inReflexiveMirror)
+ initialize
+
+ _annotations
+ }
+
def setAnnotations(annots: List[AnnotationInfo]): this.type = {
_annotations = annots
this
@@ -1562,10 +1579,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
else owner.logicallyEnclosingMember
/** The top-level class containing this symbol. */
- def toplevelClass: Symbol =
+ def enclosingTopLevelClass: Symbol =
if (owner.isPackageClass) {
if (isClass) this else moduleClass
- } else owner.toplevelClass
+ } else owner.enclosingTopLevelClass
/** Is this symbol defined in the same scope and compilation unit as `that` symbol? */
def isCoDefinedWith(that: Symbol) = (
@@ -1869,7 +1886,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
def sourceFile: AbstractFileType =
if (isModule) moduleClass.sourceFile
- else toplevelClass.sourceFile
+ else enclosingTopLevelClass.sourceFile
def sourceFile_=(f: AbstractFileType) {
abort("sourceFile_= inapplicable for " + this)
@@ -2601,7 +2618,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def defString: String = toString
override def locationString: String = ""
override def enclClass: Symbol = this
- override def toplevelClass: Symbol = this
+ override def enclosingTopLevelClass: Symbol = this
override def enclMethod: Symbol = this
override def sourceFile: AbstractFileType = null
override def ownerChain: List[Symbol] = List()
diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala
index 5bb0c98bfb..6ce6a7fac0 100644
--- a/src/compiler/scala/reflect/internal/Trees.scala
+++ b/src/compiler/scala/reflect/internal/Trees.scala
@@ -72,9 +72,9 @@ trait Trees extends api.Trees { self: SymbolTable =>
def withPosition(flag: Long, position: Position) =
copy() setPositions positions + (flag -> position)
- override def hasModifier(mod: Modifier.Value) =
+ override def hasModifier(mod: Modifier) =
hasFlag(flagOfModifier(mod))
- override def allModifiers: Set[Modifier.Value] =
+ override def modifiers: Set[Modifier] =
Modifier.values filter hasModifier
override def mapAnnotations(f: List[Tree] => List[Tree]): Modifiers =
Modifiers(flags, privateWithin, f(annotations)) setPositions positions
@@ -85,7 +85,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
def Modifiers(flags: Long, privateWithin: Name): Modifiers = Modifiers(flags, privateWithin, List())
def Modifiers(flags: Long): Modifiers = Modifiers(flags, tpnme.EMPTY)
- def Modifiers(mods: Set[Modifier.Value],
+ def Modifiers(mods: Set[Modifier],
privateWithin: Name,
annotations: List[Tree]): Modifiers = {
val flagSet = mods map flagOfModifier
@@ -231,15 +231,6 @@ trait Trees extends api.Trees { self: SymbolTable =>
def Bind(sym: Symbol, body: Tree): Bind =
Bind(sym.name, body) setSymbol sym
-
- /** 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 = {
- assert(!argss.isEmpty)
- val superRef: Tree = Select(New(tpt), nme.CONSTRUCTOR)
- (superRef /: argss) (Apply)
- }
/** 0-1 argument list new, based on a symbol.
*/
def New(sym: Symbol, args: Tree*): Tree =
@@ -251,8 +242,6 @@ trait Trees extends api.Trees { self: SymbolTable =>
def Super(sym: Symbol, mix: TypeName): Tree = Super(This(sym), mix)
- def This(sym: Symbol): Tree = This(sym.name.toTypeName) setSymbol sym
-
/** Block factory that flattens directly nested blocks.
*/
def Block(stats: Tree*): Block = {
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index 371fb8d585..cd44b700c1 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -261,6 +261,7 @@ trait Types extends api.Types { self: SymbolTable =>
def declarations = decls
def typeArguments = typeArgs
def erasedType = transformedType(this)
+ def substituteTypes(from: List[Symbol], to: List[Type]): Type = subst(from, to)
}
/** The base class for all types */
@@ -5687,7 +5688,7 @@ trait Types extends api.Types { self: SymbolTable =>
val padded = sorted map (_._2.padTo(maxSeqLength, NoType))
val transposed = padded.transpose
- val columns: List[Column[List[Type]]] = sorted.zipWithIndex map {
+ val columns: List[Column[List[Type]]] = mapWithIndex(sorted) {
case ((k, v), idx) =>
Column(str(k), (xs: List[Type]) => str(xs(idx)), true)
}
diff --git a/src/compiler/scala/reflect/runtime/JavaToScala.scala b/src/compiler/scala/reflect/runtime/JavaToScala.scala
index b4bcc52a23..4c49c0221f 100644
--- a/src/compiler/scala/reflect/runtime/JavaToScala.scala
+++ b/src/compiler/scala/reflect/runtime/JavaToScala.scala
@@ -241,16 +241,32 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
* The Scala owner of the Scala class corresponding to the Java class `jclazz`
*/
private def sOwner(jclazz: jClass[_]): Symbol = {
- if (jclazz.isMemberClass)
- followStatic(classToScala(jclazz.getEnclosingClass), jclazz.getModifiers)
- else if (jclazz.isLocalClass)
- methodToScala(jclazz.getEnclosingMethod) orElse constrToScala(jclazz.getEnclosingConstructor)
- else if (jclazz.isPrimitive || jclazz.isArray)
+ if (jclazz.isMemberClass) {
+ val jEnclosingClass = jclazz.getEnclosingClass
+ val sEnclosingClass = classToScala(jEnclosingClass)
+ followStatic(sEnclosingClass, jclazz.getModifiers)
+ } else if (jclazz.isLocalClass) {
+ val jEnclosingMethod = jclazz.getEnclosingMethod
+ if (jEnclosingMethod != null) {
+ methodToScala(jEnclosingMethod)
+ } else {
+ val jEnclosingConstructor = jclazz.getEnclosingConstructor
+ constrToScala(jEnclosingConstructor)
+ }
+ } else if (jclazz.isPrimitive || jclazz.isArray) {
ScalaPackageClass
- else if (jclazz.getPackage != null)
- packageToScala(jclazz.getPackage)
- else
+ } else if (jclazz.getPackage != null) {
+ val jPackage = jclazz.getPackage
+ packageToScala(jPackage)
+ } else {
+ // @eb: a weird classloader might return a null package for something with a non-empty package name
+ // for example, http://groups.google.com/group/scala-internals/browse_thread/thread/7be09ff8f67a1e5c
+ // in that case we could invoke packageNameToScala(jPackageName) and, probably, be okay
+ // however, I think, it's better to blow up, since weirdness of the class loader might bite us elsewhere
+ val jPackageName = jclazz.getName.substring(0, Math.max(jclazz.getName.lastIndexOf("."), 0))
+ assert(jPackageName == "")
EmptyPackageClass
+ }
}
/**
@@ -295,8 +311,10 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
* @return A Scala method object that corresponds to `jmeth`.
*/
def methodToScala(jmeth: jMethod): Symbol = methodCache.toScala(jmeth) {
- val owner = followStatic(classToScala(jmeth.getDeclaringClass), jmeth.getModifiers)
- lookup(owner, jmeth.getName) suchThat (erasesTo(_, jmeth)) orElse jmethodAsScala(jmeth)
+ val jOwner = jmeth.getDeclaringClass
+ var sOwner = classToScala(jOwner)
+ sOwner = followStatic(sOwner, jmeth.getModifiers)
+ lookup(sOwner, jmeth.getName) suchThat (erasesTo(_, jmeth)) orElse jmethodAsScala(jmeth)
}
/**
@@ -344,6 +362,18 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
pkg.moduleClass
}
+ private def scalaSimpleName(jclazz: jClass[_]): TypeName = {
+ val owner = sOwner(jclazz)
+ val enclosingClass = jclazz.getEnclosingClass
+ var prefix = if (enclosingClass != null) enclosingClass.getName else ""
+ val isObject = owner.isModuleClass && !owner.isPackageClass
+ if (isObject && !prefix.endsWith(nme.MODULE_SUFFIX_STRING)) prefix += nme.MODULE_SUFFIX_STRING
+ assert(jclazz.getName.startsWith(prefix))
+ var name = jclazz.getName.substring(prefix.length)
+ name = name.substring(name.lastIndexOf(".") + 1)
+ newTypeName(name)
+ }
+
/**
* The Scala class that corresponds to a given Java class.
* @param jclazz The Java class
@@ -353,28 +383,54 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
*/
def classToScala(jclazz: jClass[_]): Symbol = classCache.toScala(jclazz) {
val jname = javaTypeName(jclazz)
- def lookup = sOwner(jclazz).info.decl(newTypeName(jclazz.getSimpleName))
-
- if (jclazz.isMemberClass && !nme.isImplClassName(jname)) {
- val sym = lookup
- assert(sym.isType, sym+"/"+jclazz+"/"+sOwner(jclazz)+"/"+jclazz.getSimpleName)
- sym.asInstanceOf[ClassSymbol]
- }
- 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
+ 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
+ }
+ }
+
+ 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 (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
+ }
}
- 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) {
+ 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.asInstanceOf[ClassSymbol]
}
/**
@@ -453,7 +509,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
private def jclassAsScala(jclazz: jClass[_]): Symbol = jclassAsScala(jclazz, sOwner(jclazz))
private def jclassAsScala(jclazz: jClass[_], owner: Symbol): Symbol = {
- val name = newTypeName(jclazz.getSimpleName)
+ val name = scalaSimpleName(jclazz)
val completer = (clazz: Symbol, module: Symbol) => new FromJavaClassCompleter(clazz, module, jclazz)
val (clazz, module) = createClassModule(owner, name, completer)
classCache enter (jclazz, clazz)
diff --git a/src/compiler/scala/reflect/runtime/Mirror.scala b/src/compiler/scala/reflect/runtime/Mirror.scala
index 4808326902..028a660a35 100644
--- a/src/compiler/scala/reflect/runtime/Mirror.scala
+++ b/src/compiler/scala/reflect/runtime/Mirror.scala
@@ -12,28 +12,28 @@ class Mirror extends Universe with RuntimeTypes with TreeBuildUtil with ToolBoxe
import definitions._
- def classWithName(name: String): Symbol = {
+ def symbolForName(name: String): Symbol = {
val clazz = javaClass(name, defaultReflectiveClassLoader())
classToScala(clazz)
}
- def getCompanionObject(clazz: Symbol): AnyRef = {
+ def companionInstance(clazz: Symbol): AnyRef = {
val singleton = ReflectionUtils.singletonInstance(clazz.fullName, defaultReflectiveClassLoader())
singleton
}
- def getClass(obj: AnyRef): Symbol = classToScala(obj.getClass)
- def getType(obj: AnyRef): Type = typeToScala(obj.getClass)
+ def symbolOfInstance(obj: Any): Symbol = classToScala(obj.getClass)
+ def typeOfInstance(obj: Any): Type = typeToScala(obj.getClass)
// to do add getClass/getType for instances of primitive types, probably like this:
// def getClass[T <: AnyVal : Manifest](x: T): Symbol = manifest[T].getClass
- def getValue(receiver: AnyRef, field: Symbol): Any = {
+ def getValueOfField(receiver: AnyRef, field: Symbol): Any = {
fieldToJava(field).get(receiver)
}
- def setValue(receiver: AnyRef, field: Symbol, value: Any): Unit = {
+ def setValueOfField(receiver: AnyRef, field: Symbol, value: Any): Unit = {
fieldToJava(field).set(receiver, value)
}
- def invoke(receiver: AnyRef, meth: Symbol, args: Any*): Any = {
+ def invoke(receiver: AnyRef, meth: Symbol)(args: Any*): Any = {
if (meth.owner == ArrayClass) {
meth.name match {
case nme.length => return Array.getLength(receiver)
diff --git a/src/compiler/scala/reflect/runtime/ToolBoxes.scala b/src/compiler/scala/reflect/runtime/ToolBoxes.scala
index 46d890c5d1..6e671ae06e 100644
--- a/src/compiler/scala/reflect/runtime/ToolBoxes.scala
+++ b/src/compiler/scala/reflect/runtime/ToolBoxes.scala
@@ -44,17 +44,19 @@ trait ToolBoxes extends { self: Universe =>
// !!! 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))
val ownerClass = EmptyPackageClass.newClassWithInfo(newTypeName("<expression-owner>"), List(ObjectClass.tpe), newScope)
val owner = ownerClass.newLocalDummy(tree.pos)
-
- typer.atOwner(tree, owner).typed(tree, analyzer.EXPRmode, pt)
+ val ttree = typer.atOwner(tree, owner).typed(tree, analyzer.EXPRmode, pt)
+ trace("typed: ")(showAttributed(ttree))
+ 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, ScalaObjectClass.tpe), newScope, obj.moduleClass)
@@ -66,9 +68,7 @@ trait ToolBoxes extends { self: Universe =>
minfo.decls enter meth
trace("wrapping ")(defOwner(expr) -> meth)
val methdef = DefDef(meth, expr changeOwner (defOwner(expr) -> meth))
- trace("wrapped: ")(showAttributed(methdef))
- resetAllAttrs(
- ModuleDef(
+ val moduledef = ModuleDef(
obj,
Template(
List(TypeTree(ObjectClass.tpe)),
@@ -77,7 +77,11 @@ trait ToolBoxes extends { self: Universe =>
List(),
List(List()),
List(methdef),
- NoPosition)))
+ NoPosition))
+ trace("wrapped: ")(showAttributed(moduledef))
+ val cleanedUp = resetLocalAttrs(moduledef)
+ trace("cleaned up: ")(showAttributed(cleanedUp))
+ cleanedUp
}
def wrapInPackage(clazz: Tree): PackageDef =
@@ -91,7 +95,7 @@ trait ToolBoxes extends { self: Universe =>
def compileExpr(expr: Tree, fvs: List[Symbol]): String = {
val mdef = wrapInObject(expr, fvs)
- val pdef = trace("wrapped: ")(wrapInPackage(mdef))
+ val pdef = wrapInPackage(mdef)
val unit = wrapInCompilationUnit(pdef)
val run = new Run
run.compileUnits(List(unit), run.namerPhase)
@@ -104,24 +108,27 @@ trait ToolBoxes extends { self: Universe =>
def runExpr(expr: Tree): Any = {
val etpe = expr.tpe
val fvs = (expr filter isFree map (_.symbol)).distinct
-
+
reporter.reset()
val className = compileExpr(expr, fvs)
if (reporter.hasErrors) {
throw new Error("reflective compilation has failed")
}
-
+
if (settings.debug.value) println("generated: "+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)
- val result = jmeth.invoke(singleton, fvs map (sym => sym.asInstanceOf[FreeVar].value.asInstanceOf[AnyRef]): _*)
- if (etpe.typeSymbol != FunctionClass(0)) result
- else {
- val applyMeth = result.getClass.getMethod("apply")
- applyMeth.invoke(result)
- }
+ // @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]): _*)
+// 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]): _*)
}
def showAttributed(tree: Tree, printTypes: Boolean = true, printIds: Boolean = true, printKinds: Boolean = false): String = {
@@ -131,7 +138,7 @@ trait ToolBoxes extends { self: Universe =>
try {
settings.printtypes.value = printTypes
settings.uniqid.value = printIds
- settings.uniqid.value = printKinds
+ settings.Yshowsymkinds.value = printKinds
tree.toString
} finally {
settings.printtypes.value = saved1
@@ -167,7 +174,7 @@ trait ToolBoxes extends { self: Universe =>
lazy val exporter = importer.reverse
lazy val classLoader = new AbstractFileClassLoader(virtualDirectory, defaultReflectiveClassLoader)
-
+
private def importAndTypeCheck(tree: rm.Tree, expectedType: rm.Type): compiler.Tree = {
// 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
@@ -189,8 +196,8 @@ trait ToolBoxes extends { self: Universe =>
def typeCheck(tree: rm.Tree): rm.Tree =
typeCheck(tree, WildcardType.asInstanceOf[rm.Type])
- def showAttributed(tree: rm.Tree): String =
- compiler.showAttributed(importer.importTree(tree.asInstanceOf[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)
def runExpr(tree: rm.Tree, expectedType: rm.Type): Any = {
val ttree = importAndTypeCheck(tree, expectedType)
diff --git a/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala b/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala
index fc4177e956..275c85f332 100644
--- a/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala
+++ b/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala
@@ -2,7 +2,6 @@ package scala.reflect
package runtime
trait TreeBuildUtil extends Universe with api.TreeBuildUtil {
-
def staticClass(fullname: String): Symbol = definitions.getRequiredClass(fullname)
def staticModule(fullname: String): Symbol = definitions.getRequiredModule(fullname)
def thisModuleType(fullname: String) = staticModule(fullname).moduleClass.thisType
@@ -39,7 +38,7 @@ trait TreeBuildUtil extends Universe with api.TreeBuildUtil {
selectIn(owner.info, idx)
}
- def freeVar(name: String, info: Type, value: Any) = newFreeVar(newTermName(name), info, value)
+ 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)
diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala
index 04ff0c440d..3c79fcd3fb 100644
--- a/src/compiler/scala/tools/ant/Scalac.scala
+++ b/src/compiler/scala/tools/ant/Scalac.scala
@@ -90,7 +90,7 @@ class Scalac extends ScalaMatchingTask with ScalacShared {
/** Defines valid values for properties that refer to compiler phases. */
object CompilerPhase extends PermissibleValue {
- val values = List("namer", "typer", "pickler", "refchecks", "liftcode",
+ val values = List("namer", "typer", "pickler", "refchecks",
"uncurry", "tailcalls", "specialize", "explicitouter",
"erasure", "lazyvals", "lambdalift", "constructors",
"flatten", "mixin", "cleanup", "icode", "inliner",
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 797ed7e047..18735cafe2 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -37,6 +37,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
with Plugins
with PhaseAssembly
with Trees
+ with Reifiers
with TreePrinters
with DocComments
with MacroContext
@@ -124,7 +125,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 NodePrinters with ReifyPrinters {
infolevel = InfoLevel.Verbose
}
@@ -134,6 +135,7 @@ 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-------------------------
@@ -457,17 +459,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
val runsRightAfter = None
} with RefChecks
- // phaseName = "liftcode"
- object liftcode extends {
- val global: Global.this.type = Global.this
- val runsAfter = List[String]("refchecks")
- val runsRightAfter = None
- } with LiftCode
-
// phaseName = "uncurry"
override object uncurry extends {
val global: Global.this.type = Global.this
- val runsAfter = List[String]("refchecks", "liftcode")
+ val runsAfter = List[String]("refchecks")
val runsRightAfter = None
} with UnCurry
@@ -652,7 +647,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
superAccessors -> "add super accessors in traits and nested classes",
pickler -> "serialize symbol tables",
refChecks -> "reference/override checking, translate nested objects",
- liftcode -> "reify trees",
uncurry -> "uncurry, translate function values to anonymous classes",
tailCalls -> "replace tail calls by jumps",
specializeTypes -> "@specialized-driven class and method specialization",
@@ -1082,7 +1076,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
def compiles(sym: Symbol): Boolean =
if (sym == NoSymbol) false
else if (symSource.isDefinedAt(sym)) true
- else if (!sym.owner.isPackageClass) compiles(sym.toplevelClass)
+ else if (!sym.owner.isPackageClass) compiles(sym.enclosingTopLevelClass)
else if (sym.isModuleClass) compiles(sym.sourceModule)
else false
diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/ast/Reifiers.scala
index c5475fa0f2..ac6c8c4c77 100644
--- a/src/compiler/scala/tools/nsc/transform/LiftCode.scala
+++ b/src/compiler/scala/tools/nsc/ast/Reifiers.scala
@@ -4,7 +4,7 @@
*/
package scala.tools.nsc
-package transform
+package ast
import symtab._
import Flags._
@@ -13,158 +13,44 @@ import scala.collection.mutable.ListBuffer
import scala.tools.nsc.util.FreshNameCreator
import scala.runtime.ScalaRunTime.{ isAnyVal, isTuple }
-/**
- * Translate expressions of the form reflect.Code.lift(exp)
- * to the reified "reflect trees" representation of exp.
- * Also: mutable variables that are accessed from a local function are wrapped in refs.
+/** 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
*/
-abstract class LiftCode extends Transform with TypingTransformers {
-
- import global._ // the global environment
- import definitions._ // standard classes and methods
- import typer.{ typed, atOwner } // methods to type trees
-
- val symbols: global.type = global
-
- /** the following two members override abstract members in Transform */
- val phaseName: String = "liftcode"
-
- def newTransformer(unit: CompilationUnit): Transformer =
- new Codifier(unit)
-
- private lazy val MirrorMemberNames =
- ReflectRuntimeMirror.info.nonPrivateMembers filter (_.isTerm) map (_.toString) toSet
-
- // Would be nice if we could use something like this to check the names,
- // but it seems that info is unavailable when I need it.
- private def mirrorFactoryName(value: Any): Option[String] = value match {
- // Modest (inadequate) sanity check that there's a member by this name.
- case x: Product if MirrorMemberNames(x.productPrefix) =>
- Some(x.productPrefix)
- case _ =>
- Some(value.getClass.getName split """[$.]""" last) filter MirrorMemberNames
- }
- private def isMirrorMemberObject(value: Product) = value match {
- case NoType | NoPrefix | NoPosition | EmptyTree => true
- case _ => false
- }
-
- class Codifier(unit: CompilationUnit) extends TypingTransformer(unit) {
-
- val reifyDebug = settings.Yreifydebug.value
- val debugTrace = util.trace when reifyDebug
-
- val reifyCopypaste = settings.Yreifycopypaste.value
- def printCopypaste(tree: Tree) {
- import scala.reflect.api.Modifier
- import scala.reflect.api.Modifier._
-
- def copypasteModifier(mod: Modifier.Value): String = mod match {
- case mod @ (
- `protected` | `private` | `override` |
- `abstract` | `final` | `sealed` |
- `implicit` | `lazy` | `macro` |
- `case` | `trait`) => "`" + mod.toString + "`"
- case mod => mod.toString
- }
-
- // I fervently hope this is a test case or something, not anything being
- // depended upon. Of more fragile code I cannot conceive.
- for (line <- (tree.toString.split(Properties.lineSeparator) drop 2 dropRight 1)) {
- 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 StringBuilder
-
- val flags = m.group(1).toLong
- val s_flags = Flags.modifiersOfFlags(flags) map copypasteModifier mkString ", "
- if (s_flags != "")
- buf.append("Set(" + s_flags + ")")
-
- val privateWithin = "" + m.group(2)
- if (privateWithin != "")
- buf.append(", newTypeName(\"" + privateWithin + "\")")
-
- val annotations = m.group(3)
- if (annotations.nonEmpty)
- buf.append(", List(" + annotations + ")")
-
- "Modifiers(" + buf.toString + ")"
- })
- s = """setInternalFlags\((\d+)L\)""".r.replaceAllIn(s, m => {
- val flags = m.group(1).toLong
- val mods = Flags.modifiersOfFlags(flags) map copypasteModifier
- "setInternalFlags(flagsOfModifiers(List(" + mods.mkString(", ") + ")))"
- })
-
- println(s)
- }
- }
-
- override def transformUnit(unit: CompilationUnit) {
- atPhase(phase.next) {
- super.transformUnit(unit)
- }
- }
+trait Reifiers { self: Global =>
+
+ def reify(tree: Tree): Tree = {
+ 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("=======================")
+ }
- override def transform(tree: Tree): Tree = {
- val sym = tree.symbol
- tree match {
- case Apply(_, List(tree)) if sym == Code_lift => // reify Code.lift[T](expr) instances
- val saved = printTypings
- try {
- printTypings = reifyDebug
- debugTrace("transformed = ") {
- val result = localTyper.typedPos(tree.pos)(codify(super.transform(tree)))
- if (reifyCopypaste) printCopypaste(result)
- result
- }
- } finally printTypings = saved
- case _ =>
- super.transform(tree)
+ untyped
+ }
+ } finally {
+ printTypings = saved
}
- }
-
- def codify(tree: Tree): Tree = debugTrace("codified " + tree + " -> ") {
- val targetType = definitions.CodeClass.primaryConstructor.info.paramTypes.head
- val reifier = new Reifier()
- val arg = gen.mkAsInstanceOf(reifier.reifyTopLevel(tree), targetType, wrapInApply = false)
- val treetpe =
- if (tree.tpe.typeSymbol.isAnonymousClass) tree.tpe.typeSymbol.classBound
- else tree.tpe
- New(TypeTree(appliedType(definitions.CodeClass.typeConstructor, List(treetpe.widen))),
- List(List(arg)))
+ } else {
+ CannotReifyPreTyperTrees(tree)
}
}
- /**
- * Given a tree or type, generate a tree that when executed at runtime produces the original tree or type.
- * For instance: Given
- *
- * var x = 1; Code(x + 1)
- *
- * The `x + 1` expression is reified to
- *
- * $mr.Apply($mr.Select($mr.Ident($mr.freeVar("x". <Int>, x), "+"), List($mr.Literal($mr.Constant(1))))))
- *
- * Or, the term name 'abc' is reified to:
- *
- * $mr.Apply($mr.Select($mr.Ident("newTermName")), List(Literal(Constant("abc")))))
- *
- * todo: Treat embedded Code blocks by merging them into containing block
- *
- */
class Reifier() {
+ import definitions._
final val scalaPrefix = "scala."
final val localPrefix = "$local"
@@ -268,6 +154,12 @@ abstract class LiftCode extends Transform with TypingTransformers {
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)
@@ -294,9 +186,9 @@ abstract class LiftCode extends Transform with TypingTransformers {
if (sym.isTerm) {
if (reifyDebug) println("Free: " + sym)
val symtpe = lambdaLift.boxIfCaptured(sym, sym.tpe, erasedTypes = false)
- def markIfCaptured(arg: Ident): Tree =
+ def markIfCaptured(arg: Ident): Tree =
if (sym.isCapturedVariable) referenceCapturedVariable(arg) else arg
- mirrorCall("freeVar", reify(sym.name.toString), reify(symtpe), markIfCaptured(Ident(sym)))
+ mirrorCall("newFreeVar", reify(sym.name.toString), reify(symtpe), markIfCaptured(Ident(sym)))
} else {
if (reifyDebug) println("Late local: " + sym)
registerReifiableSymbol(sym)
@@ -324,7 +216,7 @@ abstract class LiftCode extends Transform with TypingTransformers {
* 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.setTypeSig), List(reifyType(sym.info)))
+ 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)))
}
@@ -375,30 +267,52 @@ abstract class LiftCode extends Transform with TypingTransformers {
}
}
+ private def definedInLiftedCode(tpe: Type) =
+ tpe exists (tp => boundSyms contains tp.typeSymbol)
+
+ private def isErased(tree: Tree) = tree match {
+ case tt: TypeTree => definedInLiftedCode(tt.tpe) && tt.original == null
+ case _ => false
+ }
+
/** Reify a tree */
private def reifyTree(tree: Tree): Tree = tree match {
case EmptyTree =>
reifyMirrorObject(EmptyTree)
- case This(_) if !(boundSyms contains tree.symbol) =>
+ case This(_) if tree.symbol != NoSymbol && !(boundSyms contains tree.symbol) =>
reifyFree(tree)
- case Ident(_) if !(boundSyms contains tree.symbol) =>
+ case Ident(_) if tree.symbol != NoSymbol && !(boundSyms contains tree.symbol) =>
if (tree.symbol.isVariable && tree.symbol.owner.isTerm) {
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) =>
- if (!(boundSyms exists (tt.tpe contains _))) mirrorCall("TypeTree", reifyType(tt.tpe))
- else if (tt.original != null) reify(tt.original)
- else mirrorCall(nme.TypeTree)
+ if (definedInLiftedCode(tt.tpe)) {
+ // erase non-essential (i.e. inferred) types
+ // reify symless counterparts of essential types
+ if (tt.original != null) reify(tt.original) else mirrorCall("TypeTree")
+ } else {
+ var rtt = mirrorCall(nme.TypeTree, reifyType(tt.tpe))
+ if (tt.original != null) {
+ val setOriginal = Select(rtt, newTermName("setOriginal"))
+ val reifiedOriginal = reify(tt.original)
+ rtt = Apply(setOriginal, List(reifiedOriginal))
+ }
+ rtt
+ }
case ta @ TypeApply(hk, ts) =>
- val thereAreOnlyTTs = ts collect { case t if !t.isInstanceOf[TypeTree] => t } isEmpty;
- val ttsAreNotEssential = ts collect { case tt: TypeTree => tt } find { tt => tt.original != null } isEmpty;
- if (thereAreOnlyTTs && ttsAreNotEssential) reifyTree(hk) else reifyProduct(ta)
- case global.emptyValDef =>
+ if (ts exists isErased) reifyTree(hk) else reifyProduct(ta)
+ case self.emptyValDef =>
mirrorSelect(nme.emptyValDef)
+ 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 _ =>
- if (tree.isDef)
+ if (tree.isDef) {
+ if (reifyDebug) println("boundSym: " + tree.symbol)
boundSyms += tree.symbol
+ }
reifyProduct(tree)
/*
@@ -414,8 +328,19 @@ abstract class LiftCode extends Transform with TypingTransformers {
* 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 =
- mirrorCall(nme.Ident, reifySymRef(tree.symbol))
+ 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 =
@@ -477,7 +402,7 @@ abstract class LiftCode extends Transform with TypingTransformers {
private def typePath(fullname: String): Tree = path(fullname, newTypeName)
private def mirrorAlias =
- ValDef(NoMods, nme.MIRROR_SHORT, TypeTree(), termPath(fullnme.MirrorPackage))
+ 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`
@@ -494,8 +419,25 @@ abstract class LiftCode extends Transform with TypingTransformers {
symDefs.toList ++ fillIns.toList
}
+ }
+
+ /** A throwable signalling a reification error */
+ class ReifierError(var pos: Position, val msg: String) extends Throwable(msg) {
+ def this(msg: String) = this(NoPosition, msg)
+ }
+
+ def CannotReifyPreTyperTrees(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 CannotReifyClassOfBoundType(tree: Tree, tpe: Type) = {
+ val msg = "cannot reify classOf[%s] which refers to a type declared inside the block being reified".format(tpe)
+ throw new ReifierError(tree.pos, msg)
+ }
- private def cannotReify(value: Any): Nothing =
- abort("don't know how to reify " + value + " of " + value.getClass)
+ def CannotReifyClassOfBoundEnum(tree: Tree, tpe: Type) = {
+ val msg = "cannot reify classOf[%s] which refers to an enum declared inside the block being reified".format(tpe)
+ throw new ReifierError(tree.pos, msg)
}
}
diff --git a/src/compiler/scala/tools/nsc/ast/ReifyPrinters.scala b/src/compiler/scala/tools/nsc/ast/ReifyPrinters.scala
new file mode 100644
index 0000000000..98135fadda
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/ReifyPrinters.scala
@@ -0,0 +1,75 @@
+/* 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 StringBuilder
+
+ val flags = m.group(1).toLong
+ val s_flags = Flags.modifiersOfFlags(flags) map (_.sourceString) mkString ", "
+ if (s_flags != "")
+ buf.append("Set(" + s_flags + ")")
+
+ val privateWithin = "" + m.group(2)
+ if (privateWithin != "")
+ buf.append(", newTypeName(\"" + privateWithin + "\")")
+
+ val annotations = m.group(3)
+ if (annotations.nonEmpty)
+ buf.append(", List(" + annotations + ")")
+
+ "Modifiers(" + buf.toString + ")"
+ })
+ 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/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index c80b07c44d..83b6252b26 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -42,8 +42,8 @@ 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.
+
+ /** 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.
@@ -208,7 +208,7 @@ trait Trees extends reflect.internal.Trees { self: Global =>
case _ => this.treeCopy.SelectFromArray(tree, qualifier, selector, erasure)
}
def ReferenceToBoxed(tree: Tree, idt: Ident) = tree match {
- case t @ ReferenceToBoxed(idt0)
+ case t @ ReferenceToBoxed(idt0)
if (idt0 == idt) => t
case _ => this.treeCopy.ReferenceToBoxed(tree, idt)
}
@@ -251,62 +251,79 @@ trait Trees extends reflect.internal.Trees { self: Global =>
}
}
- /** resets symbol and tpe fields in a tree, @see ResetAttrsTraverse
+ /** resets symbol and tpe fields in a tree, @see ResetAttrs
*/
// 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 ResetAttrsTransformer(false).transformPoly(x)
- def resetLocalAttrs[A<:Tree](x:A): A = new ResetAttrsTransformer(true).transformPoly(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)
/** A transformer which resets symbol and tpe fields of all nodes in a given tree,
* with special treatment of:
* TypeTree nodes: are replaced by their original if it exists, otherwise tpe field is reset
* to empty if it started out empty or refers to local symbols (which are erased).
* TypeApply nodes: are deleted if type arguments end up reverted to empty
- * This(pkg) notes where pkg is a pckage: these are kept.
+ * This(pkg) nodes where pkg is a package: these are kept.
*
- * (bq:) This traverser has mutable state and should be discarded after use
+ * (bq:) This transformer has mutable state and should be discarded after use
*/
- private class ResetAttrsTransformer(localOnly: Boolean) extends Transformer {
- private val erasedSyms = util.HashSet[Symbol](8)
- private def resetDef(tree: Tree) {
- if (tree.symbol != null && tree.symbol != NoSymbol)
- erasedSyms addEntry tree.symbol
- tree.symbol = NoSymbol
+ private class ResetAttrs(localOnly: Boolean) {
+ val locals = util.HashSet[Symbol](8)
+
+ class MarkLocals extends self.Traverser {
+ def markLocal(tree: Tree) =
+ if (tree.symbol != null && tree.symbol != NoSymbol)
+ locals addEntry tree.symbol
+
+ override def traverse(tree: Tree) = {
+ tree match {
+ case _: DefTree | Function(_, _) | Template(_, _, _) =>
+ markLocal(tree)
+ case _ if tree.symbol.isInstanceOf[FreeVar] =>
+ markLocal(tree)
+ case _ =>
+ ;
+ }
+
+ super.traverse(tree)
+ }
}
- override def transform(tree: Tree): Tree = super.transform {
- tree match {
- case Template(_, _, body) =>
- body foreach resetDef
- resetDef(tree)
- tree.tpe = null
- tree
- case _: DefTree | Function(_, _) | Template(_, _, _) =>
- resetDef(tree)
- tree.tpe = null
- tree
- case tpt: TypeTree =>
- if (tpt.original != null)
- tpt.original
- else if (tpt.tpe != null && (tpt.wasEmpty || (tpt.tpe exists (tp => erasedSyms contains tp.typeSymbol))))
- tpt.tpe = null
- tree
- case TypeApply(fn, args) if args map transform exists (_.isEmpty) =>
- fn
- case This(_) if tree.symbol != null && tree.symbol.isPackageClass =>
- tree
- case EmptyTree =>
- tree
- case _ =>
- if (tree.hasSymbol && (!localOnly || (erasedSyms contains tree.symbol)))
- tree.symbol = NoSymbol
- tree.tpe = null
- tree
+
+ 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
+ }
+ 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 transformPoly[T <: Tree](x: T): T = {
- val x1 = transform(x)
+
+ def transform[T <: Tree](x: T): T = {
+ new MarkLocals().traverse(x)
+
+ val trace = scala.tools.nsc.util.trace when settings.debug.value
+ val eoln = System.getProperty("line.separator")
+ trace("locals (%d total): %n".format(locals.size))(locals.toList map {" " + _} mkString eoln)
+
+ val x1 = new Transformer().transform(x)
assert(x.getClass isInstance x1)
x1.asInstanceOf[T]
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index 4478fb6128..dae264fffe 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -84,6 +84,8 @@ trait Scanners extends ScannersCommon {
abstract class Scanner extends CharArrayReader with TokenData with ScannerCommon {
private def isDigit(c: Char) = java.lang.Character isDigit c
+
+ def isAtEnd = charOffset >= buf.length
def flush = { charOffset = offset; nextChar(); this }
@@ -449,7 +451,7 @@ trait Scanners extends ScannersCommon {
case ']' =>
nextChar(); token = RBRACKET
case SU =>
- if (charOffset >= buf.length) token = EOF
+ if (isAtEnd) token = EOF
else {
syntaxError("illegal character")
nextChar()
@@ -771,10 +773,10 @@ trait Scanners extends ScannersCommon {
putChar(ch)
}
- private def getLitChars(delimiter: Char) =
- while (ch != delimiter && (ch != CR && ch != LF && ch != SU || isUnicodeEscape)) {
+ private def getLitChars(delimiter: Char) = {
+ while (ch != delimiter && !isAtEnd && (ch != SU && ch != CR && ch != LF || isUnicodeEscape))
getLitChar()
- }
+ }
/** read fractional part and exponent of floating point number
* if one is present.
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 3d650ef753..6aee52a354 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -133,7 +133,7 @@ abstract class GenICode extends SubComponent {
if (!ctx1.bb.closed) ctx1.bb.close
prune(ctx1.method)
} else
- ctx1.method.setCode(null)
+ ctx1.method.setCode(NoCode)
ctx1
case Template(_, _, body) =>
@@ -1072,6 +1072,15 @@ abstract class GenICode extends SubComponent {
targets = tmpCtx.bb :: targets
case Ident(nme.WILDCARD) =>
default = tmpCtx.bb
+ case Alternative(alts) =>
+ alts foreach {
+ case Literal(value) =>
+ tags = value.intValue :: tags
+ targets = tmpCtx.bb :: targets
+ case _ =>
+ abort("Invalid case in alternative in switch-like pattern match: " +
+ tree + " at: " + tree.pos)
+ }
case _ =>
abort("Invalid case statement in switch-like pattern match: " +
tree + " at: " + (tree.pos))
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala
index 2668e7f29f..298c9171a1 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala
@@ -177,8 +177,7 @@ trait Members {
/** method parameters */
var params: List[Local] = Nil
- // TODO - see how null is stil arriving here
- def hasCode = (code ne NoCode) && (code ne null)
+ def hasCode = code ne NoCode
def setCode(code: Code): IMethod = {
this.code = code;
this
diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala
index ea36eb03c7..efa524503c 100644
--- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala
@@ -196,11 +196,11 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
/** The start of a scaladoc code block */
protected val CodeBlockStart =
- new Regex("""(.*)((?:\{\{\{)|(?:\u000E<pre(?: [^>]*)?>\u000E))(.*)""")
+ new Regex("""(.*?)((?:\{\{\{)|(?:\u000E<pre(?: [^>]*)?>\u000E))(.*)""")
/** The end of a scaladoc code block */
protected val CodeBlockEnd =
- new Regex("""(.*)((?:\}\}\})|(?:\u000E</pre>\u000E))(.*)""")
+ new Regex("""(.*?)((?:\}\}\})|(?:\u000E</pre>\u000E))(.*)""")
/** A key used for a tag map. The key is built from the name of the tag and
* from the linked symbol if the tag has one.
@@ -250,7 +250,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
* @param remaining The lines that must still recursively be parsed.
* @param inCodeBlock Whether the next line is part of a code block (in which no tags must be read). */
def parse0 (
- docBody: String,
+ docBody: StringBuilder,
tags: Map[TagKey, List[String]],
lastTagKey: Option[TagKey],
remaining: List[String],
@@ -258,9 +258,11 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
): Comment = remaining match {
case CodeBlockStart(before, marker, after) :: ls if (!inCodeBlock) =>
- if (before.trim != "")
- parse0(docBody, tags, lastTagKey, before :: (marker + after) :: ls, false)
- else if (after.trim != "")
+ if (!before.trim.isEmpty && !after.trim.isEmpty)
+ parse0(docBody, tags, lastTagKey, before :: marker :: after :: ls, false)
+ else if (!before.trim.isEmpty)
+ parse0(docBody, tags, lastTagKey, before :: marker :: ls, false)
+ else if (!after.trim.isEmpty)
parse0(docBody, tags, lastTagKey, marker :: after :: ls, true)
else lastTagKey match {
case Some(key) =>
@@ -271,24 +273,26 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
}
parse0(docBody, tags + (key -> value), lastTagKey, ls, true)
case None =>
- parse0(docBody + endOfLine + marker, tags, lastTagKey, ls, true)
+ parse0(docBody append endOfLine append marker, tags, lastTagKey, ls, true)
}
case CodeBlockEnd(before, marker, after) :: ls =>
- if (before.trim != "")
- parse0(docBody, tags, lastTagKey, before :: (marker + after) :: ls, true)
- else if (after.trim != "")
+ if (!before.trim.isEmpty && !after.trim.isEmpty)
+ parse0(docBody, tags, lastTagKey, before :: marker :: after :: ls, true)
+ if (!before.trim.isEmpty)
+ parse0(docBody, tags, lastTagKey, before :: marker :: ls, true)
+ else if (!after.trim.isEmpty)
parse0(docBody, tags, lastTagKey, marker :: after :: ls, false)
else lastTagKey match {
case Some(key) =>
val value =
((tags get key): @unchecked) match {
- case Some(b :: bs) => (b + endOfLine + "}}}") :: bs
+ case Some(b :: bs) => (b + endOfLine + marker) :: bs
case None => oops("lastTagKey set when no tag exists for key")
}
parse0(docBody, tags + (key -> value), lastTagKey, ls, false)
case None =>
- parse0(docBody + endOfLine + marker, tags, lastTagKey, ls, false)
+ parse0(docBody append endOfLine append marker, tags, lastTagKey, ls, false)
}
case SymbolTag(name, sym, body) :: ls if (!inCodeBlock) =>
@@ -311,8 +315,9 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
parse0(docBody, tags + (key -> value), lastTagKey, ls, inCodeBlock)
case line :: ls =>
- val newBody = if (docBody == "") line else docBody + endOfLine + line
- parse0(newBody, tags, lastTagKey, ls, inCodeBlock)
+ if (docBody.length > 0) docBody append endOfLine
+ docBody append line
+ parse0(docBody, tags, lastTagKey, ls, inCodeBlock)
case Nil =>
@@ -350,7 +355,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
}
val com = createComment (
- body0 = Some(parseWiki(docBody, pos)),
+ body0 = Some(parseWiki(docBody.toString, pos)),
authors0 = allTags(SimpleTagKey("author")),
see0 = allTags(SimpleTagKey("see")),
result0 = oneTag(SimpleTagKey("return")),
@@ -374,7 +379,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
}
- parse0("", Map.empty, None, clean(comment), false)
+ parse0(new StringBuilder(comment.size), Map.empty, None, clean(comment), false)
}
@@ -385,7 +390,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
* - Removed all end-of-line whitespace.
* - Only `endOfLine` is used to mark line endings. */
def parseWiki(string: String, pos: Position): Body = {
- new WikiParser(string.toArray, pos).document()
+ new WikiParser(string, pos).document()
}
/** TODO
@@ -393,7 +398,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
* @author Ingo Maier
* @author Manohar Jonnalagedda
* @author Gilles Dubochet */
- protected final class WikiParser(val buffer: Array[Char], pos: Position) extends CharReader(buffer) { wiki =>
+ protected final class WikiParser(val buffer: String, pos: Position) extends CharReader(buffer) { wiki =>
var summaryParsed = false
@@ -411,7 +416,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
def block(): Block = {
if (checkSkipInitWhitespace("{{{"))
code()
- else if (checkSkipInitWhitespace("="))
+ else if (checkSkipInitWhitespace('='))
title()
else if (checkSkipInitWhitespace("----"))
hrule()
@@ -493,7 +498,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
def title(): Block = {
jumpWhitespace()
val inLevel = repeatJump("=")
- val text = inline(check(Array.fill(inLevel)('=')))
+ val text = inline(check("=" * inLevel))
val outLevel = repeatJump("=", inLevel)
if (inLevel != outLevel)
reportError(pos, "unbalanced or unclosed heading")
@@ -734,11 +739,11 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
val pc = char
nextChar() // read EOL
val ok = {
- checkSkipInitWhitespace(Array(endOfLine)) ||
- checkSkipInitWhitespace(Array('=')) ||
- checkSkipInitWhitespace(Array('{', '{', '{')) ||
+ checkSkipInitWhitespace(endOfLine) ||
+ checkSkipInitWhitespace('=') ||
+ checkSkipInitWhitespace("{{{") ||
checkList ||
- checkSkipInitWhitespace(Array('\u003D'))
+ checkSkipInitWhitespace('\u003D')
}
offset = poff
char = pc
@@ -751,7 +756,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
}
}
- protected sealed class CharReader(buffer: Array[Char]) { reader =>
+ protected sealed class CharReader(buffer: String) { reader =>
var char: Char = _
var offset: Int = 0
@@ -760,36 +765,37 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
if (offset >= buffer.length)
char = endOfText
else {
- char = buffer(offset)
+ char = buffer charAt offset
offset += 1
}
}
- implicit def strintToChars(s: String): Array[Char] = s.toArray
-
- def store(body: => Unit): String = {
- val pre = offset
- body
- val post = offset
- buffer.toArray.slice(pre, post).toString
+ final def check(chars: String): Boolean = {
+ val poff = offset
+ val pc = char
+ val ok = jump(chars)
+ offset = poff
+ char = pc
+ ok
}
- final def check(chars: Array[Char]): Boolean = {
+ def checkSkipInitWhitespace(c: Char): Boolean = {
val poff = offset
val pc = char
- val ok = jump(chars)
+ jumpWhitespace()
+ val ok = jump(c)
offset = poff
char = pc
ok
}
- def checkSkipInitWhitespace(chars: Array[Char]): Boolean = {
+ def checkSkipInitWhitespace(chars: String): Boolean = {
val poff = offset
val pc = char
jumpWhitespace()
val (ok0, chars0) =
- if (chars.head == ' ')
- (offset > poff, chars.tail)
+ if (chars.charAt(0) == ' ')
+ (offset > poff, chars substring 1)
else
(true, chars)
val ok = ok0 && jump(chars0)
@@ -825,16 +831,16 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
/** jumps all the characters in chars, consuming them in the process.
* @return true only if the correct characters have been jumped */
- final def jump(chars: Array[Char]): Boolean = {
+ final def jump(chars: String): Boolean = {
var index = 0
- while (index < chars.length && char == chars(index) && char != endOfText) {
+ while (index < chars.length && char == chars.charAt(index) && char != endOfText) {
nextChar()
index += 1
}
index == chars.length
}
- final def checkedJump(chars: Array[Char]): Boolean = {
+ final def checkedJump(chars: String): Boolean = {
val poff = offset
val pc = char
val ok = jump(chars)
@@ -845,7 +851,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
ok
}
- final def repeatJump(chars: Array[Char], max: Int): Int = {
+ final def repeatJump(chars: String, max: Int): Int = {
var count = 0
var more = true
while (more && count < max) {
@@ -857,7 +863,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
count
}
- final def repeatJump(chars: Array[Char]): Int = {
+ final def repeatJump(chars: String): Int = {
var count = 0
var more = true
while (more) {
@@ -878,10 +884,10 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
count
}
- final def jumpUntil(chars: Array[Char]): Int = {
+ final def jumpUntil(chars: String): Int = {
assert(chars.length > 0)
var count = 0
- val c = chars(0)
+ val c = chars.charAt(0)
while (!check(chars) && char != endOfText) {
nextChar()
while (char != c && char != endOfText) {
@@ -922,10 +928,10 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory =>
count
}
- final def readUntil(chars: Array[Char]): Int = {
+ final def readUntil(chars: String): Int = {
assert(chars.length > 0)
var count = 0
- val c = chars(0)
+ val c = chars.charAt(0)
while (!check(chars) && char != endOfText) {
readBuilder += char
nextChar()
diff --git a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
index 3bc4e1cbe1..3a605975f4 100644
--- a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
@@ -20,6 +20,7 @@ class AbstractFileClassLoader(root: AbstractFile, parent: ClassLoader)
with ScalaClassLoader
{
// private val defined = mutable.Map[String, Class[_]]()
+
override protected def trace =
sys.props contains "scala.debug.classloader"
@@ -43,6 +44,22 @@ class AbstractFileClassLoader(root: AbstractFile, parent: ClassLoader)
}
}
+ protected def dirNameToPath(name: String): String =
+ name.replace('.', '/')
+
+ protected def findAbstractDir(name: String): AbstractFile = {
+ var file: AbstractFile = root
+ val pathParts = dirNameToPath(name) split '/'
+
+ for (dirPart <- pathParts) {
+ file = file.lookupName(dirPart, true)
+ if (file == null)
+ return null
+ }
+
+ return file
+ }
+
override def getResourceAsStream(name: String) = findAbstractFile(name) match {
case null => super.getResourceAsStream(name)
case file => file.input
@@ -74,4 +91,24 @@ class AbstractFileClassLoader(root: AbstractFile, parent: ClassLoader)
// case null => super.getResource(name)
// case file => new URL(...)
// }
+
+ private val packages = mutable.Map[String, Package]()
+
+ override def definePackage(name: String, specTitle: String, specVersion: String, specVendor: String, implTitle: String, implVersion: String, implVendor: String, sealBase: URL): Package = {
+ throw new UnsupportedOperationException()
+ }
+
+ override def getPackage(name: String): Package = {
+ findAbstractDir(name) match {
+ case null => super.getPackage(name)
+ case file => packages.getOrElseUpdate(name, {
+ val ctor = classOf[Package].getDeclaredConstructor(classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[URL], classOf[ClassLoader])
+ ctor.setAccessible(true)
+ ctor.newInstance(name, null, null, null, null, null, null, null, this)
+ })
+ }
+ }
+
+ override def getPackages(): Array[Package] =
+ root.iterator.filter(_.isDirectory).map(dir => getPackage(dir.name)).toArray
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
index 567d6c2f78..6ae8d0e7d0 100644
--- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
@@ -196,7 +196,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
def foreach[U](f: Tree => U): Unit = t foreach { x => f(x) ; () }
}).toList
}
-
+
implicit def installReplTypeOps(tp: Type): ReplTypeOps = new ReplTypeOps(tp)
class ReplTypeOps(tp: Type) {
def orElse(other: => Type): Type = if (tp ne NoType) tp else other
@@ -831,7 +831,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(code)
+ showCodeIfDebugging(packaged(code))
val (success, run) = compileSourcesKeepingRun(new BatchSourceFile(label, packaged(code)))
lastRun = run
success
@@ -1078,7 +1078,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
val clazz = classOfTerm(id) getOrElse { return NoType }
val staticSym = tpe.typeSymbol
val runtimeSym = getClassIfDefined(clazz.getName)
-
+
if ((runtimeSym != NoSymbol) && (runtimeSym != staticSym) && (runtimeSym isSubClass staticSym))
runtimeSym.info
else NoType
diff --git a/src/compiler/scala/tools/nsc/io/Path.scala b/src/compiler/scala/tools/nsc/io/Path.scala
index 9efff089ba..a1b8e5e4d5 100644
--- a/src/compiler/scala/tools/nsc/io/Path.scala
+++ b/src/compiler/scala/tools/nsc/io/Path.scala
@@ -48,7 +48,7 @@ object Path {
implicit def jfile2path(jfile: JFile): Path = apply(jfile)
// java 7 style, we don't use it yet
- // object AccessMode extends Enumeration("AccessMode") {
+ // object AccessMode extends Enumeration {
// val EXECUTE, READ, WRITE = Value
// }
// def checkAccess(modes: AccessMode*): Boolean = {
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 107ffc35c6..485a1f3a5c 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -166,7 +166,7 @@ trait ScalaSettings extends AbsScalaSettings
val Ypmatdebug = BooleanSetting ("-Ypmat-debug", "Trace all pattern matcher activity.")
val Yreifycopypaste =
BooleanSetting ("-Yreify-copypaste", "Dump the reified trees in copypasteable representation.")
- val Yreifydebug = BooleanSetting ("-Yreify-debug", "Trace reification actions.")
+ val Yreifydebug = BooleanSetting ("-Yreify-debug", "Trace reification.")
val Yreplsync = BooleanSetting ("-Yrepl-sync", "Do not use asynchronous code for repl startup")
val Yrepldebug = BooleanSetting ("-Yrepl-debug", "Trace all repl activity.") .
withPostSetHook(_ => interpreter.replProps.debug setValue true)
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index ac6dca4422..a8083d7a2d 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -238,9 +238,9 @@ abstract class ClassfileParser {
val index = in.getChar(start + 1)
val name = getExternalName(in.getChar(starts(index) + 1))
//assert(name.endsWith("$"), "Not a module class: " + name)
- f = forceMangledName(name.subName(0, name.length - 1), true)
+ f = forceMangledName(name dropRight 1, true)
if (f == NoSymbol)
- f = definitions.getModule(name.subName(0, name.length - 1))
+ f = definitions.getModule(name dropRight 1)
} else {
val origName = nme.originalName(name)
val owner = if (static) ownerTpe.typeSymbol.linkedClassOfClass else ownerTpe.typeSymbol
@@ -1074,27 +1074,27 @@ abstract class ClassfileParser {
}
def enterClassAndModule(entry: InnerClassEntry, completer: global.loaders.SymbolLoader, jflags: Int) {
- val name = entry.originalName
- var sflags = toScalaClassFlags(jflags)
+ val name = entry.originalName
+ var sflags = toScalaClassFlags(jflags)
+ val owner = getOwner(jflags)
+ val scope = getScope(jflags)
+ val innerClass = owner.newClass(name.toTypeName, NoPosition, sflags) setInfo completer
+ val innerModule = owner.newModule(name.toTermName, NoPosition, sflags) setInfo completer
- val innerClass = getOwner(jflags).newClass(name.toTypeName).setInfo(completer).setFlag(sflags)
- val innerModule = getOwner(jflags).newModule(name.toTermName).setInfo(completer).setFlag(sflags)
innerModule.moduleClass setInfo global.loaders.moduleClassLoader
-
- getScope(jflags) enter innerClass
- getScope(jflags) enter innerModule
+ scope enter innerClass
+ scope enter innerModule
val decls = innerClass.enclosingPackage.info.decls
- val e = decls.lookupEntry(className(entry.externalName))
- if (e ne null) {
- //println("removing " + e)
- decls.unlink(e)
- }
- val e1 = decls.lookupEntry(className(entry.externalName).toTypeName)
- if (e1 ne null) {
- //println("removing " + e1)
- decls.unlink(e1)
+ def unlinkIfPresent(name: Name) = {
+ val e = decls lookupEntry name
+ if (e ne null)
+ decls unlink e
}
+
+ val cName = className(entry.externalName)
+ unlinkIfPresent(cName.toTermName)
+ unlinkIfPresent(cName.toTypeName)
}
for (entry <- innerClasses.values) {
@@ -1269,13 +1269,13 @@ abstract class ClassfileParser {
if ((jflags & (JAVA_ACC_PRIVATE | JAVA_ACC_PROTECTED | JAVA_ACC_PUBLIC)) == 0)
// See ticket #1687 for an example of when topLevelClass is NoSymbol: it
// apparently occurs when processing v45.3 bytecode.
- if (sym.toplevelClass != NoSymbol)
- sym.privateWithin = sym.toplevelClass.owner
+ if (sym.enclosingTopLevelClass != NoSymbol)
+ sym.privateWithin = sym.enclosingTopLevelClass.owner
// protected in java means package protected. #3946
if ((jflags & JAVA_ACC_PROTECTED) != 0)
- if (sym.toplevelClass != NoSymbol)
- sym.privateWithin = sym.toplevelClass.owner
+ if (sym.enclosingTopLevelClass != NoSymbol)
+ sym.privateWithin = sym.enclosingTopLevelClass.owner
}
@inline private def isPrivate(flags: Int) = (flags & JAVA_ACC_PRIVATE) != 0
diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala
index 4fa5b52de3..89f1cc26e0 100644
--- a/src/compiler/scala/tools/nsc/transform/Flatten.scala
+++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala
@@ -60,8 +60,8 @@ abstract class Flatten extends InfoTransform {
private val flattened = new TypeMap {
def apply(tp: Type): Type = tp match {
case TypeRef(pre, sym, args) if isFlattenablePrefix(pre) =>
- assert(args.isEmpty && sym.toplevelClass != NoSymbol, sym.ownerChain)
- typeRef(sym.toplevelClass.owner.thisType, sym, Nil)
+ assert(args.isEmpty && sym.enclosingTopLevelClass != NoSymbol, sym.ownerChain)
+ typeRef(sym.enclosingTopLevelClass.owner.thisType, sym, Nil)
case ClassInfoType(parents, decls, clazz) =>
var parents1 = parents
val decls1 = scopeTransform(clazz) {
@@ -119,7 +119,7 @@ abstract class Flatten extends InfoTransform {
val sym = tree.symbol
val tree1 = tree match {
case ClassDef(_, _, _, _) if sym.isNestedClass =>
- liftedDefs(sym.toplevelClass.owner) += tree
+ liftedDefs(sym.enclosingTopLevelClass.owner) += tree
EmptyTree
case Select(qual, name) if (sym.isStaticModule && !sym.owner.isPackageClass) =>
atPhase(phase.next) {
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 4a104857db..4012d08e42 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -1711,8 +1711,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
private def makeArguments(fun: Symbol, vparams: List[Symbol]): List[Tree] = (
//! TODO: make sure the param types are seen from the right prefix
- for ((tp, arg) <- fun.info.paramTypes zip vparams) yield
- gen.maybeMkAsInstanceOf(Ident(arg), tp, arg.tpe)
+ map2(fun.info.paramTypes, vparams)((tp, arg) => gen.maybeMkAsInstanceOf(Ident(arg), tp, arg.tpe))
)
private def findSpec(tp: Type): Type = tp match {
case TypeRef(pre, sym, _ :: _) => specializedType(tp)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index eaf1b1ffbc..3d2f86d54d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -625,7 +625,7 @@ trait Implicits {
if (context.hasErrors)
fail("typing TypeApply reported errors for the implicit tree")
else {
- val result = new SearchResult(checked, subst)
+ val result = new SearchResult(itree2, subst)
incCounter(foundImplicits)
printInference("[success] found %s for pt %s".format(result, ptInstantiated))
result
@@ -1163,7 +1163,7 @@ trait Implicits {
/* !!! 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 liftcode.Reifier()
+ val reifier = new Reifier()
val rtree = reifier.reifyTopLevel(tp1)
manifestFactoryCall("apply", tp, rtree)
*/
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index eac657da19..b97fbebec2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -228,9 +228,9 @@ trait Infer {
if (sym.isError) {
tree setSymbol sym setType ErrorType
} else {
- val topClass = context.owner.toplevelClass
+ val topClass = context.owner.enclosingTopLevelClass
if (context.unit.exists)
- context.unit.depends += sym.toplevelClass
+ context.unit.depends += sym.enclosingTopLevelClass
var sym1 = sym filter (alt => context.isAccessible(alt, pre, site.isInstanceOf[Super]))
// Console.println("check acc " + (sym, sym1) + ":" + (sym.tpe, sym1.tpe) + " from " + pre);//DEBUG
@@ -640,13 +640,7 @@ trait Infer {
case ExistentialType(tparams, qtpe) =>
isApplicable(undetparams, qtpe, argtpes0, pt)
case MethodType(params, _) =>
- val formals0 = params map { param =>
- param.tpe match {
- case TypeRef(_, sym, List(tpe)) if sym isNonBottomSubClass CodeClass => tpe
- case tpe => tpe
- }
- }
- val formals = formalTypes(formals0, argtpes0.length)
+ val formals = formalTypes(params map { _.tpe }, argtpes0.length)
def tryTupleApply: Boolean = {
// if 1 formal, 1 argtpe (a tuple), otherwise unmodified argtpes0
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index c63ae90ef6..b2ee36ee11 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -106,13 +106,16 @@ trait Macros { self: Analyzer =>
val mmeth = macroMeth(mac)
if (mmeth == NoSymbol) None
else {
- val receiverClass: mirror.Symbol = mirror.classWithName(mmeth.owner.fullName)
+ val receiverClass: mirror.Symbol = mirror.symbolForName(mmeth.owner.fullName)
val receiverObj = receiverClass.companionModule
- if (receiverObj == NoSymbol) None
+ if (receiverObj == mirror.NoSymbol) None
else {
- val receiver = mirror.getCompanionObject(receiverClass)
+ val receiver = mirror.companionInstance(receiverClass)
val rmeth = receiverObj.info.member(mirror.newTermName(mmeth.name.toString))
- Some((receiver, rmeth))
+ if (rmeth == mirror.NoSymbol) None
+ else {
+ Some((receiver, rmeth))
+ }
}
}
} catch {
@@ -137,7 +140,7 @@ trait Macros { self: Analyzer =>
}
val rawArgs: Seq[Any] = rawArgss.flatten
try {
- Some(mirror.invoke(receiver, rmeth, rawArgs: _*))
+ Some(mirror.invoke(receiver, rmeth)(rawArgs: _*))
} catch {
case ex =>
val realex = ReflectionUtils.unwrapThrowable(ex)
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala
index 44579400ff..6d31243fd0 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala
@@ -7,8 +7,7 @@ package scala.tools.nsc
package typechecker
import symtab._
-import Flags.{ CASE => _, _ }
-
+import Flags.{MUTABLE, METHOD, LABEL, SYNTHETIC}
/** Translate pattern matching into method calls (these methods form a zero-plus monad), similar in spirit to how for-comprehensions are compiled.
*
@@ -16,29 +15,16 @@ import Flags.{ CASE => _, _ }
* (lifting the body of the case into the monad using `one`).
*
* Cases are combined into a pattern match using the `orElse` combinator (the implicit failure case is expressed using the monad's `zero`).
- *
- * The monad `M` in which the pattern match is interpreted is determined by solving `implicitly[MatchingStrategy[M]]` for M.
- * Predef provides the default, `OptionMatching`
-
- * Example translation: TODO
-
- scrut match { case Person(father@Person(_, fatherName), name) if fatherName == name => }
- scrut match { case Person(father, name) => father match {case Person(_, fatherName) => }}
- Person.unapply(scrut) >> ((father, name) => (Person.unapply(father) >> (_, fatherName) => check(fatherName == name) >> (_ => body)))
-
- (a => (Person.unapply(a).>>(
- b => Person.unapply(b._1).>>(
- c => check(c._2 == b._2).>>(
- d => body)))))(scrut)
-
-TODO:
- - optimizer loops on virtpatmat compiler?
-
- - don't orElse a failure case at the end if there's a default case
- - implement spec more closely (see TODO's below)
- - fix inlining of methods in nested objects
+ * TODO:
+ * - interaction with CPS
+ * - Array patterns
+ * - implement spec more closely (see TODO's)
+ * - DCE
+ * - use manifests for type testing
+ *
* (longer-term) TODO:
+ * - user-defined unapplyProd
* - recover GADT typing by locally inserting implicit witnesses to type equalities derived from the current case, and considering these witnesses during subtyping (?)
* - recover exhaustivity and unreachability checking using a variation on the type-safe builder pattern
*/
@@ -46,26 +32,90 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
import global._
import definitions._
- class MatchTranslator(typer: Typer) extends MatchCodeGen {
- def typed(tree: Tree, mode: Int, pt: Type): Tree = typer.typed(tree, mode, pt) // for MatchCodeGen -- imports don't provide implementations for abstract members
+ object vpmName {
+ val one = newTermName("one")
+ val drop = newTermName("drop")
+ val flatMap = newTermName("flatMap")
+ val get = newTermName("get")
+ val guard = newTermName("guard")
+ val isEmpty = newTermName("isEmpty")
+ val orElse = newTermName("orElse")
+ val outer = newTermName("<outer>")
+ val runOrElse = newTermName("runOrElse")
+ val zero = newTermName("zero")
+ val __match = newTermName("__match")
+
+ def counted(str: String, i: Int) = newTermName(str+i)
+ }
+
+ object MatchTranslator {
+ def apply(typer: Typer): MatchTranslation = {
+ import typer._
+ // typing `__match` to decide which MatchTranslator to create adds 4% to quick.comp.timer
+ newTyper(context.makeImplicit(reportAmbiguousErrors = false)).silent(_.typed(Ident(vpmName.__match), EXPRmode, WildcardType), reportAmbiguousErrors = false) match {
+ case SilentResultValue(ms) => new PureMatchTranslator(typer, ms)
+ case _ => new OptimizingMatchTranslator(typer)
+ }
+ }
+ }
- import typer._
- import typeDebug.{ ptTree, ptBlock, ptLine }
+ class PureMatchTranslator(val typer: Typer, val matchStrategy: Tree) extends MatchTranslation with TreeMakers with PureCodegen
+ class OptimizingMatchTranslator(val typer: Typer) extends MatchTranslation with TreeMakers with MatchOptimizations
- def solveContextBound(contextBoundTp: Type): (Tree, Type) = {
- val solSym = NoSymbol.newTypeParameter(newTypeName("SolveImplicit$"))
- val param = solSym.setInfo(contextBoundTp.typeSymbol.typeParams(0).info.cloneInfo(solSym)) // TypeBounds(NothingClass.typeConstructor, baseTp)
- val pt = appliedType(contextBoundTp, List(param.tpeHK))
- val savedUndets = context.undetparams
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// talking to userland
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- context.undetparams = param :: context.undetparams
- val result = inferImplicit(EmptyTree, pt, false, false, context)
- context.undetparams = savedUndets
+ /** Interface with user-defined match monad?
+ * if there's a `__match` in scope, we use this as the match strategy, assuming it conforms to MatchStrategy as defined below:
+
+ type Matcher[P[_], M[+_], A] = {
+ def flatMap[B](f: P[A] => M[B]): M[B]
+ def orElse[B >: A](alternative: => M[B]): M[B]
+ }
+
+ abstract class MatchStrategy[P[_], M[+_]] {
+ // runs the matcher on the given input
+ def runOrElse[T, U](in: P[T])(matcher: P[T] => M[U]): P[U]
+
+ def zero: M[Nothing]
+ def one[T](x: P[T]): M[T]
+ def guard[T](cond: P[Boolean], then: => P[T]): M[T]
+ def isSuccess[T, U](x: P[T])(f: P[T] => M[U]): P[Boolean] // used for isDefinedAt
+ }
+
+ * P and M are derived from one's signature (`def one[T](x: P[T]): M[T]`)
+
+
+ * if no `__match` is found, we assume the following implementation (and generate optimized code accordingly)
+
+ object __match extends MatchStrategy[({type Id[x] = x})#Id, Option] {
+ def zero = None
+ def one[T](x: T) = Some(x)
+ // NOTE: guard's return type must be of the shape M[T], where M is the monad in which the pattern match should be interpreted
+ def guard[T](cond: Boolean, then: => T): Option[T] = if(cond) Some(then) else None
+ def runOrElse[T, U](x: T)(f: T => Option[U]): U = f(x) getOrElse (throw new MatchError(x))
+ def isSuccess[T, U](x: T)(f: T => Option[U]): Boolean = !f(x).isEmpty
+ }
+
+ */
+ trait MatchMonadInterface {
+ val typer: Typer
+ val matchOwner = typer.context.owner
+
+ def inMatchMonad(tp: Type): Type
+ def pureType(tp: Type): Type
+ final def matchMonadResult(tp: Type): Type =
+ tp.baseType(matchMonadSym).typeArgs match {
+ case arg :: Nil => arg
+ case _ => ErrorType
+ }
- (result.tree, result.subst.to(result.subst.from indexOf param))
- }
+ protected def matchMonadSym: Symbol
+ }
- lazy val (matchingStrategy, matchingMonadType) = solveContextBound(MatchingStrategyClass.typeConstructor)
+ trait MatchTranslation extends MatchMonadInterface { self: TreeMakers with CodegenCore =>
+ import typer.{typed, context, silent, reallyExists}
/** Implement a pattern match by turning its cases (including the implicit failure case)
* into the corresponding (monadic) extractors, and combining them with the `orElse` combinator.
@@ -75,7 +125,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
*
* NOTE: the resulting tree is not type checked, nor are nested pattern matches transformed
* thus, you must typecheck the result (and that will in turn translate nested matches)
- * this could probably optimized... (but note that the matchingStrategy must be solved for each nested patternmatch)
+ * this could probably optimized... (but note that the matchStrategy must be solved for each nested patternmatch)
*/
def translateMatch(scrut: Tree, cases: List[CaseDef], pt: Type): Tree = {
// we don't transform after typers
@@ -83,12 +133,17 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
// and the only place that emits Matches after typers is for exception handling anyway)
assert(phase.id <= currentRun.typerPhase.id, phase)
+ def repeatedToSeq(tp: Type): Type = (tp baseType RepeatedParamClass) match {
+ case TypeRef(_, RepeatedParamClass, args) => appliedType(SeqClass.typeConstructor, args)
+ case _ => tp
+ }
+
val scrutType = repeatedToSeq(elimAnonymousClass(scrut.tpe.widen))
- val scrutSym = freshSym(scrut.pos, scrutType)
+ val scrutSym = freshSym(scrut.pos, pureType(scrutType))
val okPt = repeatedToSeq(pt)
// pt = Any* occurs when compiling test/files/pos/annotDepMethType.scala with -Xexperimental
- combineCases(scrut, scrutSym, cases map translateCase(scrutSym, okPt), okPt, context.owner)
+ combineCases(scrut, scrutSym, cases map translateCase(scrutSym, okPt), okPt, matchOwner)
}
@@ -139,6 +194,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
// must use type `tp`, which is provided by extractor's result, not the type expected by binder,
// as b.info may be based on a Typed type ascription, which has not been taken into account yet by the translation
// (it will later result in a type test when `tp` is not a subtype of `b.info`)
+ // TODO: can we simplify this, together with the Bound case?
(extractor.subPatBinders, extractor.subPatTypes).zipped foreach { case (b, tp) => b setInfo tp } // println("changing "+ b +" : "+ b.info +" -> "+ tp);
// println("translateExtractorPattern checking parameter type: "+ (patBinder, patBinder.info.widen, extractor.paramType, patBinder.info.widen <:< extractor.paramType))
@@ -215,12 +271,8 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
and it binds the variable name to that value.
**/
case Bound(subpatBinder, p) =>
- // TreeMaker with empty list of trees only performs the substitution subpatBinder --> patBinder
- // println("rebind "+ subpatBinder +" to "+ patBinder)
- withSubPats(List(SubstOnlyTreeMaker(Substitution(subpatBinder, CODE.REF(patBinder)))),
- // the symbols are markers that may be used to refer to the result of the extractor in which the corresponding tree is nested
- // it's the responsibility of the treemaker to replace this symbol by a reference that
- // selects that result on the function symbol of the flatMap call that binds to the result of this extractor
+ // replace subpatBinder by patBinder (as if the Bind was not there)
+ withSubPats(List(SubstOnlyTreeMaker(subpatBinder, patBinder)),
// must be patBinder, as subpatBinder has the wrong info: even if the bind assumes a better type, this is not guaranteed until we cast
(patBinder, p)
)
@@ -266,7 +318,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
if (guard == EmptyTree) Nil
else List(GuardTreeMaker(guard))
- // TODO: 1) if we want to support a generalisation of Kotlin's patmat continue, must not hard-wire lifting into the monad (which is now done by pmgen.one),
+ // TODO: 1) if we want to support a generalisation of Kotlin's patmat continue, must not hard-wire lifting into the monad (which is now done by codegen.one),
// so that user can generate failure when needed -- use implicit conversion to lift into monad on-demand?
// to enable this, probably need to move away from Option to a monad specific to pattern-match,
// so that we can return Option's from a match without ambiguity whether this indicates failure in the monad, or just some result in the monad
@@ -379,34 +431,32 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
protected lazy val expectedLength = lastIndexingBinder - firstIndexingBinder + 1
protected lazy val minLenToCheck = if(lastIsStar) 1 else 0
protected def seqTree(binder: Symbol) = tupleSel(binder)(firstIndexingBinder+1)
- protected def tupleSel(binder: Symbol)(i: Int): Tree = pmgen.tupleSel(binder)(i)
+ protected def tupleSel(binder: Symbol)(i: Int): Tree = codegen.tupleSel(binder)(i)
// the trees that select the subpatterns on the extractor's result, referenced by `binder`
// require isSeq
protected def subPatRefsSeq(binder: Symbol): List[Tree] = {
- // only relevant if isSeq: (here to avoid capturing too much in the returned closure)
- val indexingIndices = (0 to (lastIndexingBinder-firstIndexingBinder))
- val nbIndexingIndices = indexingIndices.length
+ val indexingIndices = (0 to (lastIndexingBinder-firstIndexingBinder))
+ val nbIndexingIndices = indexingIndices.length
- // this error is checked by checkStarPatOK
- // if(isSeq) assert(firstIndexingBinder + nbIndexingIndices + (if(lastIsStar) 1 else 0) == nbSubPats, "(resultInMonad, ts, subPatTypes, subPats)= "+(resultInMonad, ts, subPatTypes, subPats))
+ // this error-condition has already been checked by checkStarPatOK:
+ // if(isSeq) assert(firstIndexingBinder + nbIndexingIndices + (if(lastIsStar) 1 else 0) == nbSubPats, "(resultInMonad, ts, subPatTypes, subPats)= "+(resultInMonad, ts, subPatTypes, subPats))
// there are `firstIndexingBinder` non-seq tuple elements preceding the Seq
(((1 to firstIndexingBinder) map tupleSel(binder)) ++
// then we have to index the binder that represents the sequence for the remaining subpatterns, except for...
- (indexingIndices map pmgen.index(seqTree(binder))) ++
+ (indexingIndices map codegen.index(seqTree(binder))) ++
// the last one -- if the last subpattern is a sequence wildcard: drop the prefix (indexed by the refs on the line above), return the remainder
(if(!lastIsStar) Nil else List(
if(nbIndexingIndices == 0) seqTree(binder)
- else pmgen.drop(seqTree(binder))(nbIndexingIndices)))).toList
+ else codegen.drop(seqTree(binder))(nbIndexingIndices)))).toList
}
// the trees that select the subpatterns on the extractor's result, referenced by `binder`
// require (nbSubPats > 0 && (!lastIsStar || isSeq))
- protected def subPatRefs(binder: Symbol): List[Tree] = {
+ protected def subPatRefs(binder: Symbol): List[Tree] =
if (nbSubPats == 0) Nil
else if (isSeq) subPatRefsSeq(binder)
else ((1 to nbSubPats) map tupleSel(binder)).toList
- }
protected def lengthGuard(binder: Symbol): Option[Tree] =
// no need to check unless it's an unapplySeq and the minimal length is non-trivially satisfied
@@ -427,7 +477,9 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
}
}
- // TODO: to be called when there's a def unapplyProd(x: T): Product_N
+ // TODO: to be called when there's a def unapplyProd(x: T): U
+ // U must have N members _1,..., _N -- the _i are type checked, call their type Ti,
+ //
// for now only used for case classes -- pretending there's an unapplyProd that's the identity (and don't call it)
class ExtractorCallProd(fun: Tree, args: List[Tree]) extends ExtractorCall(args) {
// TODO: fix the illegal type bound in pos/t602 -- type inference messes up before we get here:
@@ -439,15 +491,15 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
// private val extractorTp = if (wellKinded(fun.tpe)) fun.tpe else existentialAbstraction(origExtractorTp.typeParams, origExtractorTp.resultType)
// println("ExtractorCallProd: "+ (fun.tpe, existentialAbstraction(origExtractorTp.typeParams, origExtractorTp.resultType)))
// println("ExtractorCallProd: "+ (fun.tpe, args map (_.tpe)))
- private def extractorTp = fun.tpe
+ private def constructorTp = fun.tpe
def isTyped = fun.isTyped
// to which type should the previous binder be casted?
- def paramType = extractorTp.finalResultType
+ def paramType = constructorTp.finalResultType
def isSeq: Boolean = rawSubPatTypes.nonEmpty && isRepeatedParamType(rawSubPatTypes.last)
- protected def rawSubPatTypes = extractorTp.paramTypes
+ protected def rawSubPatTypes = constructorTp.paramTypes
// binder has type paramType
def treeMaker(binder: Symbol, pos: Position): TreeMaker = {
@@ -456,31 +508,20 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
}
/* TODO: remove special case when the following bug is fixed
-scala> :paste
-// Entering paste mode (ctrl-D to finish)
-
class Foo(x: Other) { x._1 } // BUG: can't refer to _1 if its defining class has not been type checked yet
case class Other(y: String)
-
-// Exiting paste mode, now interpreting.
-
-<console>:8: error: value _1 is not a member of Other
- class Foo(x: Other) { x._1 }
- ^
-
-scala> case class Other(y: String)
-defined class Other
-
-scala> class Foo(x: Other) { x._1 }
-defined class Foo */
+-- this is ok:
+case class Other(y: String)
+class Foo(x: Other) { x._1 } // no error in this order
+*/
override protected def tupleSel(binder: Symbol)(i: Int): Tree = { import CODE._
// reference the (i-1)th case accessor if it exists, otherwise the (i-1)th tuple component
val caseAccs = binder.info.typeSymbol.caseFieldAccessors
if (caseAccs isDefinedAt (i-1)) REF(binder) DOT caseAccs(i-1)
- else pmgen.tupleSel(binder)(i)
+ else codegen.tupleSel(binder)(i)
}
- override def toString(): String = "case class "+ (if (extractorTp eq null) fun else paramType.typeSymbol) +" with arguments "+ args
+ override def toString(): String = "case class "+ (if (constructorTp eq null) fun else paramType.typeSymbol) +" with arguments "+ args
}
class ExtractorCallRegular(extractorCallIncludingDummy: Tree, args: List[Tree]) extends ExtractorCall(args) {
@@ -495,7 +536,7 @@ defined class Foo */
def treeMaker(patBinderOrCasted: Symbol, pos: Position): TreeMaker = {
// the extractor call (applied to the binder bound by the flatMap corresponding to the previous (i.e., enclosing/outer) pattern)
val extractorApply = atPos(pos)(spliceApply(patBinderOrCasted))
- val binder = freshSym(pos, resultInMonad) // can't simplify this when subPatBinders.isEmpty, since UnitClass.tpe is definitely wrong when isSeq, and resultInMonad should always be correct since it comes directly from the extractor's result type
+ val binder = freshSym(pos, pureType(resultInMonad)) // can't simplify this when subPatBinders.isEmpty, since UnitClass.tpe is definitely wrong when isSeq, and resultInMonad should always be correct since it comes directly from the extractor's result type
ExtractorTreeMaker(extractorApply, lengthGuard(binder), binder, Substitution(subPatBinders, subPatRefs(binder)))(resultType.typeSymbol == BooleanClass)
}
@@ -524,12 +565,7 @@ defined class Foo */
// turn an extractor's result type into something `monadTypeToSubPatTypesAndRefs` understands
protected lazy val resultInMonad: Type = if(!hasLength(tpe.paramTypes, 1)) ErrorType else {
if (resultType.typeSymbol == BooleanClass) UnitClass.tpe
- else {
- val monadArgs = resultType.baseType(matchingMonadType.typeSymbol).typeArgs
- // assert(monadArgs.length == 1, "unhandled extractor type: "+ extractorTp) // TODO: overloaded unapply??
- if(monadArgs.length == 1) monadArgs(0)
- else ErrorType
- }
+ else matchMonadResult(resultType)
}
protected lazy val rawSubPatTypes =
@@ -543,81 +579,6 @@ defined class Foo */
override def toString() = extractorCall +": "+ extractorCall.tpe +" (symbol= "+ extractorCall.symbol +")."
}
- // tack an outer test onto `cond` if binder.info and expectedType warrant it
- def maybeWithOuterCheck(binder: Symbol, expectedTp: Type)(cond: Tree): Tree = { import CODE._
- if ( !((expectedTp.prefix eq NoPrefix) || expectedTp.prefix.typeSymbol.isPackageClass)
- && needsOuterTest(expectedTp, binder.info, context.owner)) {
- val expectedPrefix = expectedTp.prefix match {
- case ThisType(clazz) => THIS(clazz)
- case pre => REF(pre.prefix, pre.termSymbol)
- }
-
- // ExplicitOuter replaces `Select(q, outerSym) OBJ_EQ expectedPrefix` by `Select(q, outerAccessor(outerSym.owner)) OBJ_EQ expectedPrefix`
- // if there's an outer accessor, otherwise the condition becomes `true` -- TODO: can we improve needsOuterTest so there's always an outerAccessor?
- val outer = expectedTp.typeSymbol.newMethod(vpmName.outer) setInfo expectedTp.prefix setFlag SYNTHETIC
- val outerCheck = (Select(pmgen._asInstanceOf(binder, expectedTp), outer)) OBJ_EQ expectedPrefix
-
- // first check cond, since that should ensure we're not selecting outer on null
- pmgen.and(cond, outerCheck)
- }
- else
- cond
- }
-
- // TODO: also need to test when erasing pt loses crucial information (and if we can recover it using a manifest)
- def needsTypeTest(tp: Type, pt: Type) = !(tp <:< pt)
- def typeTest(binder: Symbol, pt: Type) = maybeWithOuterCheck(binder, pt)(pmgen._isInstanceOf(binder, pt))
-
- /** Type patterns consist of types, type variables, and wildcards. A type pattern T is of one of the following forms:
- - A reference to a class C, p.C, or T#C.
- This type pattern matches any non-null instance of the given class.
- Note that the prefix of the class, if it is given, is relevant for determining class instances.
- For instance, the pattern p.C matches only instances of classes C which were created with the path p as prefix.
- The bottom types scala.Nothing and scala.Null cannot be used as type patterns, because they would match nothing in any case.
-
- - A singleton type p.type.
- This type pattern matches only the value denoted by the path p
- (that is, a pattern match involved a comparison of the matched value with p using method eq in class AnyRef). // TODO: the actual pattern matcher uses ==, so that's what I'm using for now
- // https://issues.scala-lang.org/browse/SI-4577 "pattern matcher, still disappointing us at equality time"
-
- - A compound type pattern T1 with ... with Tn where each Ti is a type pat- tern.
- This type pattern matches all values that are matched by each of the type patterns Ti.
-
- - A parameterized type pattern T[a1,...,an], where the ai are type variable patterns or wildcards _.
- This type pattern matches all values which match T for some arbitrary instantiation of the type variables and wildcards.
- The bounds or alias type of these type variable are determined as described in (§8.3).
-
- - A parameterized type pattern scala.Array[T1], where T1 is a type pattern. // TODO
- This type pattern matches any non-null instance of type scala.Array[U1], where U1 is a type matched by T1.
- **/
-
- // generate the tree for the run-time test that follows from the fact that
- // a `scrut` of known type `scrutTp` is expected to have type `expectedTp`
- // uses maybeWithOuterCheck to check the type's prefix
- def typeAndEqualityTest(patBinder: Symbol, pt: Type): Tree = { import CODE._
- // TODO: `null match { x : T }` will yield a check that (indirectly) tests whether `null ne null`
- // don't bother (so that we don't end up with the warning "comparing values of types Null and Null using `ne' will always yield false")
- def genEqualsAndInstanceOf(sym: Symbol): Tree
- = pmgen._equals(REF(sym), patBinder) AND pmgen._isInstanceOf(patBinder, pt.widen)
-
- def isRefTp(tp: Type) = tp <:< AnyRefClass.tpe
-
- val patBinderTp = patBinder.info.widen
- def isMatchUnlessNull = isRefTp(pt) && !needsTypeTest(patBinderTp, pt)
-
- // TODO: [SPEC] type test for Array
- // TODO: use manifests to improve tests (for erased types we can do better when we have a manifest)
- pt match {
- case SingleType(_, sym) /*this implies sym.isStable*/ => genEqualsAndInstanceOf(sym) // TODO: [SPEC] the spec requires `eq` instead of `==` here
- case ThisType(sym) if sym.isModule => genEqualsAndInstanceOf(sym) // must use == to support e.g. List() == Nil
- case ThisType(sym) => REF(patBinder) OBJ_EQ This(sym)
- case ConstantType(Constant(null)) if isRefTp(patBinderTp) => REF(patBinder) OBJ_EQ NULL
- case ConstantType(const) => pmgen._equals(Literal(const), patBinder)
- case _ if isMatchUnlessNull => maybeWithOuterCheck(patBinder, pt)(REF(patBinder) OBJ_NE NULL)
- case _ => typeTest(patBinder, pt)
- }
- }
-
/** A conservative approximation of which patterns do not discern anything.
* They are discarded during the translation.
*/
@@ -643,14 +604,74 @@ defined class Foo */
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// substitution
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ trait TypedSubstitution extends MatchMonadInterface {
+ object Substitution {
+ def apply(from: Symbol, to: Tree) = new Substitution(List(from), List(to))
+ // requires sameLength(from, to)
+ def apply(from: List[Symbol], to: List[Tree]) =
+ if (from nonEmpty) new Substitution(from, to) else EmptySubstitution
+ }
+
+ class Substitution(val from: List[Symbol], val to: List[Tree]) {
+ // We must explicitly type the trees that we replace inside some other tree, since the latter may already have been typed,
+ // and will thus not be retyped. This means we might end up with untyped subtrees inside bigger, typed trees.
+ def apply(tree: Tree): Tree = {
+ // according to -Ystatistics 10% of translateMatch's time is spent in this method...
+ // since about half of the typedSubst's end up being no-ops, the check below shaves off 5% of the time spent in typedSubst
+ if (!tree.exists { case i@Ident(_) => from contains i.symbol case _ => false}) tree
+ else (new Transformer {
+ @inline private def typedIfOrigTyped(to: Tree, origTp: Type): Tree =
+ if (origTp == null || origTp == NoType) to
+ // important: only type when actually substing and when original tree was typed
+ // (don't need to use origTp as the expected type, though, and can't always do this anyway due to unknown type params stemming from polymorphic extractors)
+ else typer.typed(to, EXPRmode, WildcardType)
+
+ override def transform(tree: Tree): Tree = {
+ def subst(from: List[Symbol], to: List[Tree]): Tree =
+ if (from.isEmpty) tree
+ else if (tree.symbol == from.head) typedIfOrigTyped(to.head.shallowDuplicate, tree.tpe)
+ else subst(from.tail, to.tail)
+
+ tree match {
+ case Ident(_) => subst(from, to)
+ case _ => super.transform(tree)
+ }
+ }
+ }).transform(tree)
+ }
+
+
+ // the substitution that chains `other` before `this` substitution
+ // forall t: Tree. this(other(t)) == (this >> other)(t)
+ def >>(other: Substitution): Substitution = {
+ val (fromFiltered, toFiltered) = (from, to).zipped filter { (f, t) => !other.from.contains(f) }
+ new Substitution(other.from ++ fromFiltered, other.to.map(apply) ++ toFiltered) // a quick benchmarking run indicates the `.map(apply)` is not too costly
+ }
+ override def toString = (from zip to) mkString("Substitution(", ", ", ")")
+ }
+
+ object EmptySubstitution extends Substitution(Nil, Nil) {
+ override def apply(tree: Tree): Tree = tree
+ override def >>(other: Substitution): Substitution = other
+ }
+ }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// the making of the trees
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ trait TreeMakers extends TypedSubstitution { self: CodegenCore =>
+ def optimizeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type): (List[List[TreeMaker]], List[Tree]) =
+ (cases, Nil)
- trait TreeMakers {
- def inMatchMonad(tp: Type): Type = appliedType(matchingMonadType, List(tp))
- lazy val optimizingCodeGen = matchingMonadType.typeSymbol eq OptionClass
+ def emitSwitch(scrut: Tree, scrutSym: Symbol, cases: List[List[TreeMaker]], pt: Type): Option[Tree] =
+ None
abstract class TreeMaker {
+ /** captures the scope and the value of the bindings in patterns
+ * important *when* the substitution happens (can't accumulate and do at once after the full matcher has been constructed)
+ */
def substitution: Substitution =
if (currSub eq null) localSubstitution
else currSub
@@ -668,7 +689,6 @@ defined class Foo */
// build Tree that chains `next` after the current extractor
def chainBefore(next: Tree, pt: Type): Tree
- def treesToHoist: List[Tree] = Nil
}
case class TrivialTreeMaker(tree: Tree) extends TreeMaker {
@@ -679,71 +699,30 @@ defined class Foo */
case class BodyTreeMaker(body: Tree, matchPt: Type) extends TreeMaker {
val localSubstitution: Substitution = EmptySubstitution
def chainBefore(next: Tree, pt: Type): Tree = // assert(next eq EmptyTree)
- atPos(body.pos)(substitution(pmgen.one(body, body.tpe, matchPt))) // since SubstOnly treemakers are dropped, need to do it here
+ atPos(body.pos)(substitution(codegen.one(body, body.tpe, matchPt))) // since SubstOnly treemakers are dropped, need to do it here
}
- case class SubstOnlyTreeMaker(localSubstitution: Substitution) extends TreeMaker {
+ case class SubstOnlyTreeMaker(prevBinder: Symbol, nextBinder: Symbol) extends TreeMaker {
+ val localSubstitution = Substitution(prevBinder, CODE.REF(nextBinder))
def chainBefore(next: Tree, pt: Type): Tree = substitution(next)
}
abstract class FunTreeMaker extends TreeMaker {
val nextBinder: Symbol
-
- // for CSE (used iff optimizingCodeGen)
- // TODO: factor this out -- don't mutate treemakers
- var reused: Boolean = false
- def reusedBinders: List[Symbol] = Nil
- override def treesToHoist: List[Tree] = { import CODE._
- reusedBinders map { b => VAL(b) === pmgen.mkZero(b.info) }
- }
}
- abstract class FreshFunTreeMaker extends FunTreeMaker {
+ abstract class CondTreeMaker extends FunTreeMaker {
val pos: Position
val prevBinder: Symbol
val nextBinderTp: Type
- lazy val nextBinder = freshSym(pos, nextBinderTp)
- lazy val localSubstitution = Substitution(List(prevBinder), List(CODE.REF(nextBinder)))
- }
-
- // TODO: factor out optimization-specific stuff into codegen
- abstract class CondTreeMaker extends FreshFunTreeMaker { import CODE._
val cond: Tree
val res: Tree
- // for CSE (used iff optimizingCodeGen)
- // must set reused before!
- override lazy val reusedBinders = if(reused) List(freshSym(pos, BooleanClass.tpe, "rc") setFlag MUTABLE, nextBinder setFlag MUTABLE) else Nil
- def storedCond = reusedBinders(0)
- def storedRes = reusedBinders(1)
+ lazy val nextBinder = freshSym(pos, nextBinderTp)
+ lazy val localSubstitution = Substitution(List(prevBinder), List(CODE.REF(nextBinder)))
def chainBefore(next: Tree, pt: Type): Tree =
- if (!reused)
- atPos(pos)(pmgen.flatMapCond(cond, res, nextBinder, nextBinderTp, substitution(next)))
- else { // for CSE (used iff optimizingCodeGen)
- IF (cond) THEN BLOCK(
- storedCond === TRUE,
- storedRes === res,
- substitution(next).duplicate // TODO: finer-grained dup'ing
- ) ELSE pmgen.zero
- }
- }
-
- // for CSE (used iff optimizingCodeGen)
- case class ReusingCondTreeMaker(dropped_priors: List[(TreeMaker, Option[TreeMaker])]) extends TreeMaker { import CODE._
- lazy val localSubstitution = {
- val (from, to) = dropped_priors.collect {case (dropped: CondTreeMaker, Some(prior: CondTreeMaker)) => (dropped.nextBinder, REF(prior.storedRes))}.unzip
- val oldSubs = dropped_priors.collect {case (dropped: TreeMaker, _) => dropped.substitution}
- oldSubs.foldLeft(Substitution(from, to))(_ >> _)
- }
-
- def chainBefore(next: Tree, pt: Type): Tree = {
- val cond = REF(dropped_priors.reverse.collectFirst{case (_, Some(ctm: CondTreeMaker)) => ctm}.get.storedCond)
-
- IF (cond) THEN BLOCK(
- substitution(next).duplicate // TODO: finer-grained duplication -- MUST duplicate though, or we'll get VerifyErrors since sharing trees confuses lambdalift, and its confusion it emits illegal casts (diagnosed by Grzegorz: checkcast T ; invokevirtual S.m, where T not a subtype of S)
- ) ELSE pmgen.zero
- }
+ atPos(pos)(codegen.flatMapCond(cond, res, nextBinder, nextBinderTp, substitution(next)))
}
/**
@@ -754,12 +733,13 @@ defined class Foo */
* in this function's body, and all the subsequent ones, references to the symbols in `from` will be replaced by the corresponding tree in `to`
*/
case class ExtractorTreeMaker(extractor: Tree, extraCond: Option[Tree], nextBinder: Symbol, localSubstitution: Substitution)(extractorReturnsBoolean: Boolean) extends FunTreeMaker {
- def chainBefore(next: Tree, pt: Type): Tree = atPos(extractor.pos)(
- if (extractorReturnsBoolean) pmgen.flatMapCond(extractor, CODE.UNIT, nextBinder, nextBinder.info.widen, substitution(condAndNext(next)))
- else pmgen.flatMap(extractor, pmgen.fun(nextBinder, substitution(condAndNext(next))))
- )
-
- private def condAndNext(next: Tree): Tree = extraCond map (pmgen.condOptimized(_, next)) getOrElse next
+ def chainBefore(next: Tree, pt: Type): Tree = {
+ val condAndNext = extraCond map (codegen.ifThenElseZero(_, next)) getOrElse next
+ atPos(extractor.pos)(
+ if (extractorReturnsBoolean) codegen.flatMapCond(extractor, CODE.UNIT, nextBinder, nextBinder.info.widen, substitution(condAndNext))
+ else codegen.flatMap(extractor, nextBinder, substitution(condAndNext))
+ )
+ }
override def toString = "X"+(extractor, nextBinder)
}
@@ -768,21 +748,42 @@ defined class Foo */
case class ProductExtractorTreeMaker(prevBinder: Symbol, extraCond: Option[Tree], localSubstitution: Substitution) extends TreeMaker { import CODE._
def chainBefore(next: Tree, pt: Type): Tree = {
val nullCheck = REF(prevBinder) OBJ_NE NULL
- val cond = extraCond match {
- case None => nullCheck
- case Some(c) => nullCheck AND c
- }
- pmgen.condOptimized(cond, substitution(next))
+ val cond = extraCond map (nullCheck AND _) getOrElse nullCheck
+ codegen.ifThenElseZero(cond, substitution(next))
}
override def toString = "P"+(prevBinder, extraCond getOrElse "", localSubstitution)
}
+ // tack an outer test onto `cond` if binder.info and expectedType warrant it
+ def maybeWithOuterCheck(binder: Symbol, expectedTp: Type)(cond: Tree): Tree = { import CODE._
+ if ( !((expectedTp.prefix eq NoPrefix) || expectedTp.prefix.typeSymbol.isPackageClass)
+ && needsOuterTest(expectedTp, binder.info, matchOwner)) {
+ val expectedPrefix = expectedTp.prefix match {
+ case ThisType(clazz) => THIS(clazz)
+ case pre => REF(pre.prefix, pre.termSymbol)
+ }
+
+ // ExplicitOuter replaces `Select(q, outerSym) OBJ_EQ expectedPrefix` by `Select(q, outerAccessor(outerSym.owner)) OBJ_EQ expectedPrefix`
+ // if there's an outer accessor, otherwise the condition becomes `true` -- TODO: can we improve needsOuterTest so there's always an outerAccessor?
+ val outer = expectedTp.typeSymbol.newMethod(vpmName.outer) setInfo expectedTp.prefix setFlag SYNTHETIC
+ val outerCheck = (Select(codegen._asInstanceOf(binder, expectedTp), outer)) OBJ_EQ expectedPrefix
+
+ // first check cond, since that should ensure we're not selecting outer on null
+ codegen.and(cond, outerCheck)
+ }
+ else
+ cond
+ }
+
+ // TODO: also need to test when erasing pt loses crucial information (and if we can recover it using a manifest)
+ def needsTypeTest(tp: Type, pt: Type) = !(tp <:< pt)
+ private def typeTest(binder: Symbol, pt: Type) = maybeWithOuterCheck(binder, pt)(codegen._isInstanceOf(binder, pt))
// need to substitute since binder may be used outside of the next extractor call (say, in the body of the case)
case class TypeTestTreeMaker(prevBinder: Symbol, nextBinderTp: Type, pos: Position) extends CondTreeMaker {
val cond = typeTest(prevBinder, nextBinderTp)
- val res = pmgen._asInstanceOf(prevBinder, nextBinderTp)
+ val res = codegen._asInstanceOf(prevBinder, nextBinderTp)
override def toString = "TT"+(prevBinder, nextBinderTp)
}
@@ -790,8 +791,58 @@ defined class Foo */
case class TypeAndEqualityTestTreeMaker(prevBinder: Symbol, patBinder: Symbol, pt: Type, pos: Position) extends CondTreeMaker {
val nextBinderTp = glb(List(patBinder.info.widen, pt))
+ /** Type patterns consist of types, type variables, and wildcards. A type pattern T is of one of the following forms:
+ - A reference to a class C, p.C, or T#C.
+ This type pattern matches any non-null instance of the given class.
+ Note that the prefix of the class, if it is given, is relevant for determining class instances.
+ For instance, the pattern p.C matches only instances of classes C which were created with the path p as prefix.
+ The bottom types scala.Nothing and scala.Null cannot be used as type patterns, because they would match nothing in any case.
+
+ - A singleton type p.type.
+ This type pattern matches only the value denoted by the path p
+ (that is, a pattern match involved a comparison of the matched value with p using method eq in class AnyRef). // TODO: the actual pattern matcher uses ==, so that's what I'm using for now
+ // https://issues.scala-lang.org/browse/SI-4577 "pattern matcher, still disappointing us at equality time"
+
+ - A compound type pattern T1 with ... with Tn where each Ti is a type pat- tern.
+ This type pattern matches all values that are matched by each of the type patterns Ti.
+
+ - A parameterized type pattern T[a1,...,an], where the ai are type variable patterns or wildcards _.
+ This type pattern matches all values which match T for some arbitrary instantiation of the type variables and wildcards.
+ The bounds or alias type of these type variable are determined as described in (§8.3).
+
+ - A parameterized type pattern scala.Array[T1], where T1 is a type pattern. // TODO
+ This type pattern matches any non-null instance of type scala.Array[U1], where U1 is a type matched by T1.
+ **/
+
+ // generate the tree for the run-time test that follows from the fact that
+ // a `scrut` of known type `scrutTp` is expected to have type `expectedTp`
+ // uses maybeWithOuterCheck to check the type's prefix
+ private def typeAndEqualityTest(patBinder: Symbol, pt: Type): Tree = { import CODE._
+ // TODO: `null match { x : T }` will yield a check that (indirectly) tests whether `null ne null`
+ // don't bother (so that we don't end up with the warning "comparing values of types Null and Null using `ne' will always yield false")
+ def genEqualsAndInstanceOf(sym: Symbol): Tree
+ = codegen._equals(REF(sym), patBinder) AND codegen._isInstanceOf(patBinder, pt.widen)
+
+ def isRefTp(tp: Type) = tp <:< AnyRefClass.tpe
+
+ val patBinderTp = patBinder.info.widen
+ def isMatchUnlessNull = isRefTp(pt) && !needsTypeTest(patBinderTp, pt)
+
+ // TODO: [SPEC] type test for Array
+ // TODO: use manifests to improve tests (for erased types we can do better when we have a manifest)
+ pt match {
+ case SingleType(_, sym) /*this implies sym.isStable*/ => genEqualsAndInstanceOf(sym) // TODO: [SPEC] the spec requires `eq` instead of `==` here
+ case ThisType(sym) if sym.isModule => genEqualsAndInstanceOf(sym) // must use == to support e.g. List() == Nil
+ case ThisType(sym) => REF(patBinder) OBJ_EQ This(sym)
+ case ConstantType(Constant(null)) if isRefTp(patBinderTp) => REF(patBinder) OBJ_EQ NULL
+ case ConstantType(const) => codegen._equals(Literal(const), patBinder)
+ case _ if isMatchUnlessNull => maybeWithOuterCheck(patBinder, pt)(REF(patBinder) OBJ_NE NULL)
+ case _ => typeTest(patBinder, pt)
+ }
+ }
+
val cond = typeAndEqualityTest(patBinder, pt)
- val res = pmgen._asInstanceOf(patBinder, nextBinderTp)
+ val res = codegen._asInstanceOf(patBinder, nextBinderTp)
override def toString = "TET"+(patBinder, pt)
}
@@ -801,7 +852,7 @@ defined class Foo */
// NOTE: generate `patTree == patBinder`, since the extractor must be in control of the equals method (also, patBinder may be null)
// equals need not be well-behaved, so don't intersect with pattern's (stabilized) type (unlike MaybeBoundTyped's accumType, where it's required)
- val cond = pmgen._equals(patTree, prevBinder)
+ val cond = codegen._equals(patTree, prevBinder)
val res = CODE.REF(prevBinder)
override def toString = "ET"+(prevBinder, patTree)
}
@@ -836,7 +887,7 @@ defined class Foo */
if (canDuplicate) {
altss map {altTreeMakers =>
combineExtractors(altTreeMakers :+ TrivialTreeMaker(substitution(next).duplicate), pt)
- } reduceLeft pmgen.typedOrElse(pt)
+ } reduceLeft codegen.typedOrElse(pt)
} else {
val rest = freshSym(pos, functionType(List(), inMatchMonad(pt)), "rest")
// rest.info.member(nme.apply).withAnnotation(AnnotationInfo(ScalaInlineClass.tpe, Nil, Nil))
@@ -848,7 +899,7 @@ defined class Foo */
)
BLOCK(
VAL(rest) === Function(Nil, substitution(next)),
- combinedAlts reduceLeft pmgen.typedOrElse(pt)
+ combinedAlts reduceLeft codegen.typedOrElse(pt)
)
}
)
@@ -857,14 +908,239 @@ defined class Foo */
case class GuardTreeMaker(guardTree: Tree) extends TreeMaker {
val localSubstitution: Substitution = EmptySubstitution
- def chainBefore(next: Tree, pt: Type): Tree = pmgen.flatMapGuard(substitution(guardTree), next)
+ def chainBefore(next: Tree, pt: Type): Tree = codegen.flatMapGuard(substitution(guardTree), next)
override def toString = "G("+ guardTree +")"
}
+ def removeSubstOnly(makers: List[TreeMaker]) = makers filterNot (_.isInstanceOf[SubstOnlyTreeMaker])
+
+ // a foldLeft to accumulate the localSubstitution left-to-right
+ // it drops SubstOnly tree makers, since their only goal in life is to propagate substitutions to the next tree maker, which is fullfilled by propagateSubstitution
+ def propagateSubstitution(treeMakers: List[TreeMaker], initial: Substitution): List[TreeMaker] = {
+ var accumSubst: Substitution = initial
+ treeMakers foreach { maker =>
+ maker incorporateOuterSubstitution accumSubst
+ accumSubst = maker.substitution
+ }
+ removeSubstOnly(treeMakers)
+ }
+
+ // calls propagateSubstitution on the treemakers
+ def combineCases(scrut: Tree, scrutSym: Symbol, casesRaw: List[List[TreeMaker]], pt: Type, owner: Symbol): Tree = fixerUpper(owner, scrut.pos){
+ val casesUnOpt = casesRaw map (propagateSubstitution(_, EmptySubstitution)) // drops SubstOnlyTreeMakers, since their effect is now contained in the TreeMakers that follow them
+
+ emitSwitch(scrut, scrutSym, casesUnOpt, pt).getOrElse{
+ val (matcher, hasDefault, toHoist) =
+ if (casesUnOpt nonEmpty) {
+ // when specified, need to propagate pt explicitly (type inferencer can't handle it)
+ val optPt =
+ if (isFullyDefined(pt)) inMatchMonad(pt)
+ else NoType
+
+ // do this check on casesUnOpt, since DCE will eliminate trivial cases like `case _ =>`, even if they're the last one
+ // exhaustivity and reachability must be checked before optimization as well
+ val hasDefault = casesUnOpt.nonEmpty && {
+ val nonTrivLast = casesUnOpt.last
+ nonTrivLast.nonEmpty && nonTrivLast.head.isInstanceOf[BodyTreeMaker]
+ }
+
+ val (cases, toHoist) = optimizeCases(scrutSym, casesUnOpt, pt)
+
+ val combinedCases =
+ cases.map(combineExtractors(_, pt)).reduceLeft(codegen.typedOrElse(optPt))
+
+ (combinedCases, hasDefault, toHoist)
+ } else (codegen.zero, false, Nil)
+
+ val expr = codegen.runOrElse(scrut, scrutSym, matcher, if (isFullyDefined(pt)) pt else NoType, hasDefault)
+ if (toHoist isEmpty) expr
+ else Block(toHoist, expr)
+ }
+ }
+
+ // combineExtractors changes the current substitution's of the tree makers in `treeMakers`
+ // requires propagateSubstitution(treeMakers) has been called
+ def combineExtractors(treeMakers: List[TreeMaker], pt: Type): Tree =
+ treeMakers.foldRight (EmptyTree: Tree) (_.chainBefore(_, pt))
+
+ // TODO: do this during tree construction, but that will require tracking the current owner in treemakers
+ // TODO: assign more fine-grained positions
+ // fixes symbol nesting, assigns positions
+ private def fixerUpper(origOwner: Symbol, pos: Position) = new Traverser {
+ currentOwner = origOwner
+
+ override def traverse(t: Tree) {
+ if (t != EmptyTree && t.pos == NoPosition) {
+ t.setPos(pos)
+ }
+ t match {
+ case Function(_, _) if t.symbol == NoSymbol =>
+ t.symbol = currentOwner.newAnonymousFunctionValue(t.pos)
+ // println("new symbol for "+ (t, t.symbol.ownerChain))
+ case Function(_, _) if (t.symbol.owner == NoSymbol) || (t.symbol.owner == origOwner) =>
+ // println("fundef: "+ (t, t.symbol.ownerChain, currentOwner.ownerChain))
+ t.symbol.owner = currentOwner
+ case d : DefTree if (d.symbol != NoSymbol) && ((d.symbol.owner == NoSymbol) || (d.symbol.owner == origOwner)) => // don't indiscriminately change existing owners! (see e.g., pos/t3440, pos/t3534, pos/unapplyContexts2)
+ // println("def: "+ (d, d.symbol.ownerChain, currentOwner.ownerChain))
+ if(d.symbol.isLazy) { // for lazy val's accessor -- is there no tree??
+ assert(d.symbol.lazyAccessor != NoSymbol && d.symbol.lazyAccessor.owner == d.symbol.owner, d.symbol.lazyAccessor)
+ d.symbol.lazyAccessor.owner = currentOwner
+ }
+ if(d.symbol.moduleClass ne NoSymbol)
+ d.symbol.moduleClass.owner = currentOwner
+
+ d.symbol.owner = currentOwner
+ // case _ if (t.symbol != NoSymbol) && (t.symbol ne null) =>
+ // println("untouched "+ (t, t.getClass, t.symbol.ownerChain, currentOwner.ownerChain))
+ case _ =>
+ }
+ super.traverse(t)
+ }
+
+ // override def apply
+ // println("before fixerupper: "+ xTree)
+ // currentRun.trackerFactory.snapshot()
+ // println("after fixerupper")
+ // currentRun.trackerFactory.snapshot()
+ }
+ }
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// generate actual trees
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ trait CodegenCore extends MatchMonadInterface {
+ private var ctr = 0
+ def freshSym(pos: Position, tp: Type = NoType, prefix: String = "x") = {ctr += 1;
+ // assert(owner ne null)
+ // assert(owner ne NoSymbol)
+ NoSymbol.newTermSymbol(vpmName.counted(prefix, ctr), pos) setInfo repackExistential(tp)
+ }
+
+ // codegen relevant to the structure of the translation (how extractors are combined)
+ trait AbsCodegen {
+ def runOrElse(scrut: Tree, scrutSym: Symbol, matcher: Tree, resTp: Type, hasDefault: Boolean): Tree
+ def one(res: Tree, bodyPt: Type, matchPt: Type): Tree
+ def zero: Tree
+ def flatMap(prev: Tree, b: Symbol, next: Tree): Tree
+ def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree
+
+ def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, nextBinderTp: Type, next: Tree): Tree
+ def flatMapGuard(cond: Tree, next: Tree): Tree
+
+ def fun(arg: Symbol, body: Tree): Tree
+ def ifThenElseZero(c: Tree, then: Tree): Tree
+ def _equals(checker: Tree, binder: Symbol): Tree
+ def _asInstanceOf(b: Symbol, tp: Type): Tree
+ def mkZero(tp: Type): Tree
+
+ def tupleSel(binder: Symbol)(i: Int): Tree
+ def index(tgt: Tree)(i: Int): Tree
+ def drop(tgt: Tree)(n: Int): Tree
+ def and(a: Tree, b: Tree): Tree
+ def _isInstanceOf(b: Symbol, tp: Type): Tree
+ }
+
+ def codegen: AbsCodegen
+
+ def typesConform(tp: Type, pt: Type) = ((tp eq pt) || (tp <:< pt))
+
+ abstract class CommonCodegen extends AbsCodegen { import CODE._
+ def fun(arg: Symbol, body: Tree): Tree = Function(List(ValDef(arg)), body)
+ def genTypeApply(tfun: Tree, args: Type*): Tree = if(args contains NoType) tfun else TypeApply(tfun, args.toList map TypeTree)
+ def tupleSel(binder: Symbol)(i: Int): Tree = (REF(binder) DOT nme.productAccessorName(i)) // make tree that accesses the i'th component of the tuple referenced by binder
+ def index(tgt: Tree)(i: Int): Tree = tgt APPLY (LIT(i))
+ def drop(tgt: Tree)(n: Int): Tree = (tgt DOT vpmName.drop) (LIT(n))
+ def _equals(checker: Tree, binder: Symbol): Tree = checker MEMBER_== REF(binder) // NOTE: checker must be the target of the ==, that's the patmat semantics for ya
+ def and(a: Tree, b: Tree): Tree = a AND b
+ def ifThenElseZero(c: Tree, then: Tree): Tree = IF (c) THEN then ELSE zero
+
+ // the force is needed mainly to deal with the GADT typing hack (we can't detect it otherwise as tp nor pt need contain an abstract type, we're just casting wildly)
+ def _asInstanceOf(t: Tree, tp: Type, force: Boolean = false): Tree = { val tpX = repackExistential(tp)
+ if (!force && (t.tpe ne NoType) && t.isTyped && typesConform(t.tpe, tpX)) t //{ println("warning: emitted redundant asInstanceOf: "+(t, t.tpe, tp)); t } //.setType(tpX)
+ else gen.mkAsInstanceOf(t, tpX, true, false)
+ }
+
+ def _isInstanceOf(b: Symbol, tp: Type): Tree = gen.mkIsInstanceOf(REF(b), repackExistential(tp), true, false)
+ // { val tpX = repackExistential(tp)
+ // if (typesConform(b.info, tpX)) { println("warning: emitted spurious isInstanceOf: "+(b, tp)); TRUE }
+ // else gen.mkIsInstanceOf(REF(b), tpX, true, false)
+ // }
+
+ def _asInstanceOf(b: Symbol, tp: Type): Tree = { val tpX = repackExistential(tp)
+ if (typesConform(b.info, tpX)) REF(b) //{ println("warning: emitted redundant asInstanceOf: "+(b, b.info, tp)); REF(b) } //.setType(tpX)
+ else gen.mkAsInstanceOf(REF(b), tpX, true, false)
+ }
+
+ // duplicated out of frustration with cast generation
+ def mkZero(tp: Type): Tree = {
+ tp.typeSymbol match {
+ case UnitClass => Literal(Constant())
+ case BooleanClass => Literal(Constant(false))
+ case FloatClass => Literal(Constant(0.0f))
+ case DoubleClass => Literal(Constant(0.0d))
+ case ByteClass => Literal(Constant(0.toByte))
+ case ShortClass => Literal(Constant(0.toShort))
+ case IntClass => Literal(Constant(0))
+ case LongClass => Literal(Constant(0L))
+ case CharClass => Literal(Constant(0.toChar))
+ case _ => gen.mkAsInstanceOf(Literal(Constant(null)), tp, any = true, wrapInApply = false) // the magic incantation is true/false here
+ }
+ }
+ }
+ }
+
+ trait PureMatchMonadInterface extends MatchMonadInterface {
+ val matchStrategy: Tree
+
+ def inMatchMonad(tp: Type): Type = appliedType(oneSig, List(tp)).finalResultType
+ def pureType(tp: Type): Type = appliedType(oneSig, List(tp)).paramTypes.head
+ protected def matchMonadSym = oneSig.finalResultType.typeSymbol
+
+ import CODE._
+ def __match(n: Name): SelectStart = matchStrategy DOT n
+
+ private lazy val oneSig: Type =
+ typer.typed(__match(vpmName.one), EXPRmode | POLYmode | TAPPmode | FUNmode, WildcardType).tpe // TODO: error message
+ }
+
+ trait PureCodegen extends CodegenCore with PureMatchMonadInterface {
+ def codegen: AbsCodegen = pureCodegen
+
+ object pureCodegen extends CommonCodegen { import CODE._
+ //// methods in MatchingStrategy (the monad companion) -- used directly in translation
+ // __match.runOrElse(`scrut`)(`scrutSym` => `matcher`)
+ def runOrElse(scrut: Tree, scrutSym: Symbol, matcher: Tree, resTp: Type, hasDefault: Boolean): Tree
+ = __match(vpmName.runOrElse) APPLY (scrut) APPLY (fun(scrutSym, matcher))
+ // __match.one(`res`)
+ def one(res: Tree, bodyPt: Type, matchPt: Type): Tree = (__match(vpmName.one)) (res)
+ // __match.zero
+ def zero: Tree = __match(vpmName.zero)
+ // __match.guard(`c`, `then`)
+ def guard(c: Tree, then: Tree, tp: Type): Tree = __match(vpmName.guard) APPLY (c, then)
+
+ //// methods in the monad instance -- used directly in translation
+ // `prev`.flatMap(`b` => `next`)
+ def flatMap(prev: Tree, b: Symbol, next: Tree): Tree = (prev DOT vpmName.flatMap)(fun(b, next))
+ // `thisCase`.orElse(`elseCase`)
+ def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree = (thisCase DOT vpmName.orElse) APPLY (elseCase)
+ // __match.guard(`cond`, `res`).flatMap(`nextBinder` => `next`)
+ def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, nextBinderTp: Type, next: Tree): Tree = flatMap(guard(cond, res, nextBinderTp), nextBinder, next)
+ // __match.guard(`guardTree`, ()).flatMap((_: P[Unit]) => `next`)
+ def flatMapGuard(guardTree: Tree, next: Tree): Tree = flatMapCond(guardTree, CODE.UNIT, freshSym(guardTree.pos, pureType(UnitClass.tpe)), pureType(UnitClass.tpe), next)
+ }
+ }
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// OPTIMIZATIONS
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// decisions, decisions
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ trait TreeMakerApproximation extends TreeMakers { self: CodegenCore =>
object Test {
var currId = 0
}
@@ -957,25 +1233,16 @@ defined class Foo */
override def toString = testedPath +" (<: && ==) "+ pt +"#"+ id
}
- /** a flow-sensitive, generalised, common sub-expression elimination
- * reuse knowledge from performed tests
- * the only sub-expressions we consider are the conditions and results of the three tests (type, type&equality, equality)
- * when a sub-expression is share, it is stored in a mutable variable
- * the variable is floated up so that its scope includes all of the program that shares it
- * we generalize sharing to implication, where b reuses a if a => b and priors(a) => priors(b) (the priors of a sub expression form the path through the decision tree)
- *
- * intended to be generalised to exhaustivity/reachability checking
- */
- def doCSE(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type): List[List[TreeMaker]] = {
+ def approximateMatch(root: Symbol, cases: List[List[TreeMaker]]): List[List[Test]] = {
// a variable in this set should never be replaced by a tree that "does not consist of a selection on a variable in this set" (intuitively)
- val pointsToBound = collection.mutable.HashSet(prevBinder)
+ val pointsToBound = collection.mutable.HashSet(root)
// the substitution that renames variables to variables in pointsToBound
var normalize: Substitution = EmptySubstitution
// replaces a variable (in pointsToBound) by a selection on another variable in pointsToBound
// TODO check:
- // pointsToBound -- accumSubst.from == Set(prevBinder) && (accumSubst.from.toSet -- pointsToBound) isEmpty
+ // pointsToBound -- accumSubst.from == Set(root) && (accumSubst.from.toSet -- pointsToBound) isEmpty
var accumSubst: Substitution = EmptySubstitution
val trees = new collection.mutable.HashSet[Tree]
@@ -1031,12 +1298,28 @@ defined class Foo */
| GuardTreeMaker(_)
| ProductExtractorTreeMaker(_, Some(_), _) => Havoc
case AlternativesTreeMaker(_, _, _) => Havoc // TODO: can do better here
- case SubstOnlyTreeMaker(_) => Top
+ case SubstOnlyTreeMaker(_, _) => Top
case BodyTreeMaker(_, _) => Havoc
}, tm)
}
- val testss = cases.map { _ map approximateTreeMaker }
+ cases.map { _ map approximateTreeMaker }
+ }
+ }
+
+////
+ trait CommonSubconditionElimination extends TreeMakerApproximation { self: OptimizedCodegen =>
+ /** a flow-sensitive, generalised, common sub-expression elimination
+ * reuse knowledge from performed tests
+ * the only sub-expressions we consider are the conditions and results of the three tests (type, type&equality, equality)
+ * when a sub-expression is share, it is stored in a mutable variable
+ * the variable is floated up so that its scope includes all of the program that shares it
+ * we generalize sharing to implication, where b reuses a if a => b and priors(a) => priors(b) (the priors of a sub expression form the path through the decision tree)
+ *
+ * intended to be generalised to exhaustivity/reachability checking
+ */
+ def doCSE(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type): List[List[TreeMaker]] = {
+ val testss = approximateMatch(prevBinder, cases)
// interpret:
val dependencies = new collection.mutable.LinkedHashMap[Test, Set[Cond]]
@@ -1067,7 +1350,11 @@ defined class Foo */
// then, collapse these contiguous sequences of reusing tests
// store the result of the final test and the intermediate results in hoisted mutable variables (TODO: optimize: don't store intermediate results that aren't used)
// replace each reference to a variable originally bound by a collapsed test by a reference to the hoisted variable
- testss map { tests =>
+ val reused = new collection.mutable.HashMap[TreeMaker, ReusedCondTreeMaker]
+ var okToCall = false
+ val reusedOrOrig = (tm: TreeMaker) => {assert(okToCall); reused.getOrElse(tm, tm)}
+
+ val res = testss map { tests =>
var currDeps = Set[Cond]()
val (sharedPrefix, suffix) = tests span { test =>
(test.cond eq Top) || (for(
@@ -1079,18 +1366,67 @@ defined class Foo */
}
val collapsedTreeMakers = if (sharedPrefix.nonEmpty) { // even sharing prefixes of length 1 brings some benefit (overhead-percentage for compiler: 26->24%, lib: 19->16%)
- for (test <- sharedPrefix; reusedTest <- test.reuses; if reusedTest.treeMaker.isInstanceOf[FunTreeMaker])
- reusedTest.treeMaker.asInstanceOf[FunTreeMaker].reused = true
+ for (test <- sharedPrefix; reusedTest <- test.reuses) reusedTest.treeMaker match {
+ case reusedCTM: CondTreeMaker => reused(reusedCTM) = ReusedCondTreeMaker(reusedCTM)
+ case _ =>
+ }
+
// println("sharedPrefix: "+ sharedPrefix)
for (lastShared <- sharedPrefix.reverse.dropWhile(_.cond eq Top).headOption;
lastReused <- lastShared.reuses)
- yield ReusingCondTreeMaker(sharedPrefix map (t => (t.treeMaker, t.reuses map (_.treeMaker)))) :: suffix.map(_.treeMaker)
+ yield ReusingCondTreeMaker(sharedPrefix, reusedOrOrig) :: suffix.map(_.treeMaker)
} else None
collapsedTreeMakers getOrElse tests.map(_.treeMaker) // sharedPrefix need not be empty (but it only contains Top-tests, which are dropped above)
}
+ okToCall = true // TODO: remove (debugging)
+
+ res mapConserve (_ mapConserve reusedOrOrig)
+ }
+
+ object ReusedCondTreeMaker {
+ def apply(orig: CondTreeMaker) = new ReusedCondTreeMaker(orig.prevBinder, orig.nextBinder, orig.cond, orig.res, orig.pos)
+ }
+ class ReusedCondTreeMaker(prevBinder: Symbol, val nextBinder: Symbol, cond: Tree, res: Tree, pos: Position) extends TreeMaker { import CODE._
+ lazy val localSubstitution = Substitution(List(prevBinder), List(CODE.REF(nextBinder)))
+ lazy val storedCond = freshSym(pos, BooleanClass.tpe, "rc") setFlag MUTABLE
+ lazy val treesToHoist: List[Tree] = {
+ nextBinder setFlag MUTABLE
+ List(storedCond, nextBinder) map { b => VAL(b) === codegen.mkZero(b.info) }
+ }
+
+ // TODO: finer-grained duplication
+ def chainBefore(next: Tree, pt: Type): Tree = // assert(codegen eq optimizedCodegen)
+ atPos(pos)(optimizedCodegen.flatMapCondStored(cond, storedCond, res, nextBinder, substitution(next).duplicate))
+ }
+
+ case class ReusingCondTreeMaker(sharedPrefix: List[Test], toReused: TreeMaker => TreeMaker) extends TreeMaker { import CODE._
+ lazy val dropped_priors = sharedPrefix map (t => (toReused(t.treeMaker), t.reuses map (test => toReused(test.treeMaker))))
+ lazy val localSubstitution = {
+ val (from, to) = dropped_priors.collect {
+ case (dropped: CondTreeMaker, Some(prior: ReusedCondTreeMaker)) =>
+ (dropped.nextBinder, REF(prior.nextBinder))
+ }.unzip
+ val oldSubs = dropped_priors.collect {
+ case (dropped: TreeMaker, _) =>
+ dropped.substitution
+ }
+ oldSubs.foldLeft(Substitution(from, to))(_ >> _)
+ }
+
+ def chainBefore(next: Tree, pt: Type): Tree = {
+ val cond = REF(dropped_priors.reverse.collectFirst{case (_, Some(ctm: ReusedCondTreeMaker)) => ctm}.get.storedCond)
+
+ IF (cond) THEN BLOCK(
+ substitution(next).duplicate // TODO: finer-grained duplication -- MUST duplicate though, or we'll get VerifyErrors since sharing trees confuses lambdalift, and its confusion it emits illegal casts (diagnosed by Grzegorz: checkcast T ; invokevirtual S.m, where T not a subtype of S)
+ ) ELSE codegen.zero
+ }
}
+ }
+
+ //// DCE
+ trait DeadCodeElimination extends TreeMakers { self: CodegenCore =>
// TODO: non-trivial dead-code elimination
// e.g., the following match should compile to a simple instanceof:
// case class Ident(name: String)
@@ -1099,21 +1435,10 @@ defined class Foo */
// do minimal DCE
cases
}
+ }
-
- def removeSubstOnly(makers: List[TreeMaker]) = makers filterNot (_.isInstanceOf[SubstOnlyTreeMaker])
-
- // a foldLeft to accumulate the localSubstitution left-to-right
- // it drops SubstOnly tree makers, since their only goal in life is to propagate substitutions to the next tree maker, which is fullfilled by propagateSubstitution
- def propagateSubstitution(treeMakers: List[TreeMaker], initial: Substitution): List[TreeMaker] = {
- var accumSubst: Substitution = initial
- treeMakers foreach { maker =>
- maker incorporateOuterSubstitution accumSubst
- accumSubst = maker.substitution
- }
- removeSubstOnly(treeMakers)
- }
-
+ //// SWITCHES
+ trait SwitchEmission extends TreeMakers with OptimizedMatchMonadInterface { self: CodegenCore =>
object SwitchablePattern { def unapply(pat: Tree) = pat match {
case Literal(Constant((_: Byte ) | (_: Short) | (_: Int ) | (_: Char ))) => true // TODO: Java 7 allows strings in switches
case _ => false
@@ -1128,23 +1453,35 @@ defined class Foo */
// }
// }
- def emitSwitch(scrut: Tree, scrutSym: Symbol, cases: List[List[TreeMaker]], pt: Type): Option[Tree] = if (!optimizingCodeGen) None else {
+ private val switchableTpes = Set(ByteClass.tpe, ShortClass.tpe, IntClass.tpe, CharClass.tpe)
+
+ override def emitSwitch(scrut: Tree, scrutSym: Symbol, cases: List[List[TreeMaker]], pt: Type): Option[Tree] = {
def sequence[T](xs: List[Option[T]]): Option[List[T]] =
if (xs exists (_.isEmpty)) None else Some(xs.flatten)
+ def isSwitchableTpe(tpe: Type): Boolean =
+ switchableTpes contains tpe
+ def switchableConstToInt(x: Tree): Tree = {
+ val Literal(const) = x
+ const.tag match {
+ case IntTag => x
+ case ByteTag | ShortTag | CharTag => Literal(Constant(const.intValue))
+ }
+ }
+
val caseDefs = cases map { makers =>
removeSubstOnly(makers) match {
// default case (don't move this to unfold, as it may only occur on the top level, not as an alternative -- well, except in degenerate matches)
case (btm@BodyTreeMaker(body, _)) :: Nil =>
Some(CaseDef(Ident(nme.WILDCARD), EmptyTree, btm.substitution(body)))
// constant
- case (EqualityTestTreeMaker(_, const@SwitchablePattern(), _)) :: (btm@BodyTreeMaker(body, _)) :: Nil => import CODE._
- Some(CaseDef(const, EmptyTree, btm.substitution(body)))
+ case (EqualityTestTreeMaker(_, const@SwitchablePattern(), _)) :: (btm@BodyTreeMaker(body, _)) :: Nil =>
+ Some(CaseDef(switchableConstToInt(const), EmptyTree, btm.substitution(body)))
// alternatives
case AlternativesTreeMaker(_, altss, _) :: (btm@BodyTreeMaker(body, _)) :: Nil => // assert(currLabel.isEmpty && nextLabel.isEmpty)
val caseConstants = altss map {
case EqualityTestTreeMaker(_, const@SwitchablePattern(), _) :: Nil =>
- Some(const)
+ Some(switchableConstToInt(const))
case _ =>
None
}
@@ -1158,200 +1495,58 @@ defined class Foo */
}
}
- sequence(caseDefs) map { caseDefs =>
- import CODE._
- val matcher = BLOCK(
- VAL(scrutSym) === scrut, // TODO: type test for switchable type if patterns allow switch but the scrutinee doesn't
- Match(REF(scrutSym), caseDefs) // match on scrutSym, not scrut to avoid duplicating scrut
- )
-
- // matcher filter (tree => tree.tpe == null) foreach println
- // treeBrowser browse matcher
- matcher // set type to avoid recursion in typedMatch
- }
- }
-
- def optimizeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type): List[List[TreeMaker]] =
- doCSE(prevBinder, doDCE(prevBinder, cases, pt), pt)
-
- // calls propagateSubstitution on the treemakers
- def combineCases(scrut: Tree, scrutSym: Symbol, casesRaw: List[List[TreeMaker]], pt: Type, owner: Symbol): Tree = fixerUpper(owner, scrut.pos){
- val casesUnOpt = casesRaw map (propagateSubstitution(_, EmptySubstitution)) // drops SubstOnlyTreeMakers, since their effect is now contained in the TreeMakers that follow them
-
- emitSwitch(scrut, scrutSym, casesUnOpt, pt).getOrElse{
- var toHoist = List[Tree]()
- val (matcher, hasDefault) =
- if (casesUnOpt nonEmpty) {
- // when specified, need to propagate pt explicitly (type inferencer can't handle it)
- val optPt =
- if (isFullyDefined(pt)) inMatchMonad(pt)
- else NoType
-
- // do this check on casesUnOpt, since DCE will eliminate trivial cases like `case _ =>`, even if they're the last one
- // exhaustivity and reachability must be checked before optimization as well
- val hasDefault = casesUnOpt.nonEmpty && {
- val nonTrivLast = casesUnOpt.last
- nonTrivLast.nonEmpty && nonTrivLast.head.isInstanceOf[BodyTreeMaker]
+ if (!isSwitchableTpe(scrut.tpe))
+ None // TODO: emit a cast of the scrutinee and a switch on the cast scrutinee if patterns allow switch but the type of the scrutinee doesn't
+ else {
+ sequence(caseDefs) map { caseDefs =>
+ import CODE._
+ val caseDefsWithDefault = {
+ def isDefault(x: CaseDef): Boolean = x match {
+ case CaseDef(Ident(nme.WILDCARD), EmptyTree, _) => true
+ case _ => false
}
-
- val cases =
- if (optimizingCodeGen) optimizeCases(scrutSym, casesUnOpt, pt)
- else casesUnOpt
-
- val combinedCases =
- cases.map(combineExtractors(_, pt)).reduceLeft(pmgen.typedOrElse(optPt))
-
- toHoist = (for (treeMakers <- cases; tm <- treeMakers; hoisted <- tm.treesToHoist) yield hoisted).toList
-
- (pmgen.fun(scrutSym, combinedCases), hasDefault)
- } else (pmgen.zero, false)
-
- val expr = pmgen.runOrElse(scrut, matcher, scrutSym.info, if (isFullyDefined(pt)) pt else NoType, hasDefault)
- if (toHoist isEmpty) expr
- else Block(toHoist, expr)
- }
- }
-
- // combineExtractors changes the current substitution's of the tree makers in `treeMakers`
- // requires propagateSubstitution(treeMakers) has been called
- def combineExtractors(treeMakers: List[TreeMaker], pt: Type): Tree =
- treeMakers.foldRight (EmptyTree: Tree) (_.chainBefore(_, pt))
-
-
-
- // TODO: do this during tree construction, but that will require tracking the current owner in treemakers
- // TODO: assign more fine-grained positions
- // fixes symbol nesting, assigns positions
- private def fixerUpper(origOwner: Symbol, pos: Position) = new Traverser {
- currentOwner = origOwner
-
- override def traverse(t: Tree) {
- if (t != EmptyTree && t.pos == NoPosition) {
- t.setPos(pos)
- }
- t match {
- case Function(_, _) if t.symbol == NoSymbol =>
- t.symbol = currentOwner.newAnonymousFunctionValue(t.pos)
- // println("new symbol for "+ (t, t.symbol.ownerChain))
- case Function(_, _) if (t.symbol.owner == NoSymbol) || (t.symbol.owner == origOwner) =>
- // println("fundef: "+ (t, t.symbol.ownerChain, currentOwner.ownerChain))
- t.symbol.owner = currentOwner
- case d : DefTree if (d.symbol != NoSymbol) && ((d.symbol.owner == NoSymbol) || (d.symbol.owner == origOwner)) => // don't indiscriminately change existing owners! (see e.g., pos/t3440, pos/t3534, pos/unapplyContexts2)
- // println("def: "+ (d, d.symbol.ownerChain, currentOwner.ownerChain))
- if(d.symbol.isLazy) { // for lazy val's accessor -- is there no tree??
- assert(d.symbol.lazyAccessor != NoSymbol && d.symbol.lazyAccessor.owner == d.symbol.owner, d.symbol.lazyAccessor)
- d.symbol.lazyAccessor.owner = currentOwner
+ val hasDefault = caseDefs exists isDefault
+ if (hasDefault) caseDefs else {
+ val default = atPos(scrut.pos) { DEFAULT ==> MATCHERROR(REF(scrutSym)) }
+ caseDefs :+ default
}
- if(d.symbol.moduleClass ne NoSymbol)
- d.symbol.moduleClass.owner = currentOwner
-
- d.symbol.owner = currentOwner
- // case _ if (t.symbol != NoSymbol) && (t.symbol ne null) =>
- // println("untouched "+ (t, t.getClass, t.symbol.ownerChain, currentOwner.ownerChain))
- case _ =>
+ }
+ val matcher = BLOCK(
+ if (scrut.tpe != IntClass.tpe) {
+ scrutSym setInfo IntClass.tpe
+ VAL(scrutSym) === (scrut DOT nme.toInt)
+ } else {
+ VAL(scrutSym) === scrut
+ },
+ Match(REF(scrutSym), caseDefsWithDefault) // match on scrutSym, not scrut to avoid duplicating scrut
+ )
+ // matcher filter (tree => tree.tpe == null) foreach println
+ // treeBrowser browse matcher
+ matcher // set type to avoid recursion in typedMatch
}
- super.traverse(t)
- }
-
- // override def apply
- // println("before fixerupper: "+ xTree)
- // currentRun.trackerFactory.snapshot()
- // println("after fixerupper")
- // currentRun.trackerFactory.snapshot()
- }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// substitution
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- object Substitution {
- def apply(from: Symbol, to: Tree) = new Substitution(List(from), List(to))
- // requires sameLength(from, to)
- def apply(from: List[Symbol], to: List[Tree]) =
- if (from nonEmpty) new Substitution(from, to) else EmptySubstitution
- }
-
- class Substitution(val from: List[Symbol], val to: List[Tree]) {
- def apply(tree: Tree): Tree = typedSubst(tree, from, to)
-
- // the substitution that chains `other` before `this` substitution
- // forall t: Tree. this(other(t)) == (this >> other)(t)
- def >>(other: Substitution): Substitution = {
- val (fromFiltered, toFiltered) = (from, to).zipped filter { (f, t) => !other.from.contains(f) }
- new Substitution(other.from ++ fromFiltered, other.to.map(apply) ++ toFiltered) // a quick benchmarking run indicates the `.map(apply)` is not too costly
}
- override def toString = (from zip to) mkString("Substitution(", ", ", ")")
}
-
- object EmptySubstitution extends Substitution(Nil, Nil) {
- override def apply(tree: Tree): Tree = tree
- override def >>(other: Substitution): Substitution = other
- }
-
-
- def matchingMonadType: Type
- def typedSubst(tree: Tree, from: List[Symbol], to: List[Tree]): Tree
- def freshSym(pos: Position, tp: Type = NoType, prefix: String = "x"): Symbol
- def typeAndEqualityTest(patBinder: Symbol, pt: Type): Tree
- def typeTest(binder: Symbol, pt: Type): Tree
-
- // codegen relevant to the structure of the translation (how extractors are combined)
- trait AbsCodeGen { import CODE.UNIT
- def runOrElse(scrut: Tree, matcher: Tree, scrutTp: Type, resTp: Type, hasDefault: Boolean): Tree
- def flatMap(a: Tree, b: Tree): Tree
- def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, nextBinderTp: Type, next: Tree): Tree
- def flatMapGuard(cond: Tree, next: Tree): Tree
- def fun(arg: Symbol, body: Tree): Tree
- def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree
- def zero: Tree
- def one(res: Tree, bodyPt: Type, matchPt: Type): Tree
- def condOptimized(c: Tree, then: Tree): Tree
- def _equals(checker: Tree, binder: Symbol): Tree
- def _asInstanceOf(b: Symbol, tp: Type): Tree
- def mkZero(tp: Type): Tree
- }
-
- def pmgen: AbsCodeGen
- def typed(tree: Tree, mode: Int, pt: Type): Tree // implemented in MatchTranslator
}
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// generate actual trees
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- trait MatchCodeGen extends TreeMakers {
- lazy val pmgen: CommonCodeGen with MatchingStrategyGen with MonadInstGen =
- if (optimizingCodeGen) (new CommonCodeGen with OptimizedCodeGen {})
- else (new CommonCodeGen with MatchingStrategyGen with MonadInstGen {})
-
- import CODE._
-
- trait MatchingStrategyGen { self: CommonCodeGen with MatchingStrategyGen with MonadInstGen =>
- // methods in MatchingStrategy (the monad companion) -- used directly in translation
- def runOrElse(scrut: Tree, matcher: Tree, scrutTp: Type, resTp: Type, hasDefault: Boolean): Tree = genTypeApply(matchingStrategy DOT vpmName.runOrElse, scrutTp, resTp) APPLY (scrut) APPLY (matcher) // matchingStrategy.runOrElse(scrut)(matcher)
- // *only* used to wrap the RHS of a body (isDefinedAt synthesis relies on this)
- def one(res: Tree, bodyPt: Type, matchPt: Type): Tree = (matchingStrategy DOT vpmName.one) (_asInstanceOf(res, bodyPt, force = true)) // matchingStrategy.one(res), like one, but blow this one away for isDefinedAt (since it's the RHS of a case)
- def zero: Tree = matchingStrategy DOT vpmName.zero // matchingStrategy.zero
- def guard(c: Tree, then: Tree, tp: Type): Tree = genTypeApply((matchingStrategy DOT vpmName.guard), repackExistential(tp)) APPLY (c, then) // matchingStrategy.guard[tp](c, then)
- }
+ trait OptimizedMatchMonadInterface extends MatchMonadInterface {
+ override def inMatchMonad(tp: Type): Type = optionType(tp)
+ override def pureType(tp: Type): Type = tp
+ override protected def matchMonadSym = OptionClass
+ }
- trait MonadInstGen { self: CommonCodeGen with MatchingStrategyGen with MonadInstGen =>
- // methods in the monad instance -- used directly in translation
- def flatMap(a: Tree, b: Tree): Tree = (a DOT vpmName.flatMap)(b)
- def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree = (genTypeApply(thisCase DOT vpmName.orElse, pt)) APPLY (elseCase)
+ trait OptimizedCodegen extends CodegenCore with TypedSubstitution with OptimizedMatchMonadInterface {
+ override def codegen: AbsCodegen = optimizedCodegen
- // TODO: the trees generated by flatMapCond and flatMapGuard may need to be distinguishable by exhaustivity checking -- they aren't right now
- def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol,
- nextBinderTp: Type, next: Tree): Tree = flatMap(guard(cond, res, nextBinderTp), fun(nextBinder, next))
- def flatMapGuard(guardTree: Tree, next: Tree): Tree = flatMapCond(guardTree, CODE.UNIT, freshSym(guardTree.pos, UnitClass.tpe), UnitClass.tpe, next)
- }
+ // trait AbsOptimizedCodegen extends AbsCodegen {
+ // def flatMapCondStored(cond: Tree, condSym: Symbol, res: Tree, nextBinder: Symbol, next: Tree): Tree
+ // }
+ // def optimizedCodegen: AbsOptimizedCodegen
// when we know we're targetting Option, do some inlining the optimizer won't do
- // `o.flatMap(f)` becomes `if(o == None) None else f(o.get)`, similarly for orElse and guard
- // this is a special instance of the advanced inlining optimization that takes a method call on
- // an object of a type that only has two concrete subclasses, and inlines both bodies, guarded by an if to distinguish the two cases
- // this trait overrides ALL of the methods of MatchingStrategyGen with MonadInstGen
- trait OptimizedCodeGen extends CommonCodeGen with MatchingStrategyGen with MonadInstGen {
+ // for example, `o.flatMap(f)` becomes `if(o == None) None else f(o.get)`, similarly for orElse and guard
+ // this is a special instance of the advanced inlining optimization that takes a method call on
+ // an object of a type that only has two concrete subclasses, and inlines both bodies, guarded by an if to distinguish the two cases
+ object optimizedCodegen extends CommonCodegen /*with AbsOptimizedCodegen*/ { import CODE._
lazy val zeroSym = freshSym(NoPosition, optionType(NothingClass.tpe), "zero")
/** Inline runOrElse and get rid of Option allocations
@@ -1363,23 +1558,22 @@ defined class Foo */
@inline private def dontStore(tp: Type) = (tp.typeSymbol eq UnitClass) || (tp.typeSymbol eq NothingClass)
lazy val keepGoing = freshSym(NoPosition, BooleanClass.tpe, "keepGoing") setFlag MUTABLE
lazy val matchRes = freshSym(NoPosition, AnyClass.tpe, "matchRes") setFlag MUTABLE
- override def runOrElse(scrut: Tree, matcher: Tree, scrutTp: Type, resTp: Type, hasDefault: Boolean) = {
- val Function(List(x: ValDef), body) = matcher
+ def runOrElse(scrut: Tree, scrutSym: Symbol, matcher: Tree, resTp: Type, hasDefault: Boolean) = {
matchRes.info = if (resTp ne NoType) resTp.widen else AnyClass.tpe // we don't always know resTp, and it might be AnyVal, in which case we can't assign NULL
if (dontStore(resTp)) matchRes resetFlag MUTABLE // don't assign to Unit-typed var's, in fact, make it a val -- conveniently also works around SI-5245
BLOCK(
- VAL(zeroSym) === REF(NoneModule), // TODO: can we just get rid of explicitly emitted zero? don't know how to do that as a local rewrite...
- VAL(x.symbol) === scrut, // reuse the symbol of the function's argument to avoid creating a fresh one and substituting it for x.symbol in body -- the owner structure is repaired by fixerUpper
+ VAL(zeroSym) === REF(NoneModule), // TODO: can we just get rid of explicitly emitted zero? don't know how to do that as a local rewrite...
+ VAL(scrutSym) === scrut, // reuse the symbol of the function's argument to avoid creating a fresh one and substituting it for scrutSym in `matcher` -- the owner structure is repaired by fixerUpper
VAL(matchRes) === mkZero(matchRes.info), // must cast to deal with GADT typing, hence the private mkZero above
VAL(keepGoing) === TRUE,
- body,
+ matcher,
if(hasDefault) REF(matchRes)
- else (IF (REF(keepGoing)) THEN MATCHERROR(REF(x.symbol)) ELSE REF(matchRes))
+ else (IF (REF(keepGoing)) THEN MATCHERROR(REF(scrutSym)) ELSE REF(matchRes))
)
}
// only used to wrap the RHS of a body
- override def one(res: Tree, bodyPt: Type, matchPt: Type): Tree = {
+ def one(res: Tree, bodyPt: Type, matchPt: Type): Tree = {
BLOCK(
if (dontStore(matchPt)) res // runOrElse hasn't been called yet, so matchRes.isMutable is irrelevant, also, tp may be a subtype of resTp used in runOrElse...
else (REF(matchRes) === res), // _asInstanceOf(res, tp.widen, force = true)
@@ -1388,194 +1582,57 @@ defined class Foo */
)
}
- override def zero: Tree = REF(zeroSym)
-
- // guard is only used by flatMapCond and flatMapGuard, which are overridden
- override def guard(c: Tree, then: Tree, tp: Type): Tree = throw new NotImplementedError("guard is never called by optimizing codegen")
+ def zero: Tree = REF(zeroSym)
- override def flatMap(opt: Tree, fun: Tree): Tree = fun match {
- case Function(List(x: ValDef), body) =>
- val tp = inMatchMonad(x.symbol.tpe)
- val vs = freshSym(opt.pos, tp, "o")
- val isEmpty = tp member vpmName.isEmpty
- val get = tp member vpmName.get
- val v = VAL(vs) === opt
+ def flatMap(prev: Tree, b: Symbol, next: Tree): Tree = {
+ val tp = inMatchMonad(b.tpe)
+ val prevSym = freshSym(prev.pos, tp, "o")
+ val isEmpty = tp member vpmName.isEmpty
+ val get = tp member vpmName.get
- BLOCK(
- v,
- IF (vs DOT isEmpty) THEN zero ELSE typedSubst(body, List(x.symbol), List(vs DOT get)) // must be isEmpty and get as we don't control the target of the call (could be the result of a user-defined extractor)
- )
- case _ => println("huh?")
- (opt DOT vpmName.flatMap)(fun)
+ BLOCK(
+ VAL(prevSym) === prev,
+ IF (prevSym DOT isEmpty) THEN zero ELSE Substitution(b, prevSym DOT get)(next) // must be isEmpty and get as we don't control the target of the call (could be the result of a user-defined extractor)
+ )
}
- override def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree = {
+ def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree = {
BLOCK(
thisCase,
IF (REF(keepGoing)) THEN elseCase ELSE zero // leave trailing zero for now, otherwise typer adds () anyway
)
}
- override def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, nextBinderTp: Type, next: Tree): Tree =
+ def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, nextBinderTp: Type, next: Tree): Tree =
IF (cond) THEN BLOCK(
VAL(nextBinder) === res,
next
) ELSE zero
- override def flatMapGuard(guardTree: Tree, next: Tree): Tree =
- IF (guardTree) THEN next ELSE zero
- }
-
- @inline private def typedIfOrigTyped(to: Tree, origTp: Type): Tree =
- if (origTp == null || origTp == NoType) to
- // important: only type when actually substing and when original tree was typed
- // (don't need to use origTp as the expected type, though, and can't always do this anyway due to unknown type params stemming from polymorphic extractors)
- else typed(to, EXPRmode, WildcardType)
-
- // We must explicitly type the trees that we replace inside some other tree, since the latter may already have been typed,
- // and will thus not be retyped. This means we might end up with untyped subtrees inside bigger, typed trees.
- def typedSubst(tree: Tree, from: List[Symbol], to: List[Tree]): Tree = {
- // according to -Ystatistics 10% of translateMatch's time is spent in this method...
- // since about half of the typedSubst's end up being no-ops, the check below shaves off 5% of the time spent in typedSubst
- if (!tree.exists { case i@Ident(_) => from contains i.symbol case _ => false}) tree
- else (new Transformer {
- override def transform(tree: Tree): Tree = {
- def subst(from: List[Symbol], to: List[Tree]): Tree =
- if (from.isEmpty) tree
- else if (tree.symbol == from.head) typedIfOrigTyped(to.head.shallowDuplicate, tree.tpe)
- else subst(from.tail, to.tail)
-
- tree match {
- case Ident(_) => subst(from, to)
- case _ => super.transform(tree)
- }
- }
- }).transform(tree)
- }
-
- var ctr = 0
- def freshSym(pos: Position, tp: Type = NoType, prefix: String = "x") = {ctr += 1;
- // assert(owner ne null)
- // assert(owner ne NoSymbol)
- NoSymbol.newTermSymbol(vpmName.counted(prefix, ctr), pos) setInfo repackExistential(tp)
- }
-
- def repeatedToSeq(tp: Type): Type = (tp baseType RepeatedParamClass) match {
- case TypeRef(_, RepeatedParamClass, args) => appliedType(SeqClass.typeConstructor, args)
- case _ => tp
- }
+ def flatMapCondStored(cond: Tree, condSym: Symbol, res: Tree, nextBinder: Symbol, next: Tree): Tree =
+ IF (cond) THEN BLOCK(
+ condSym === TRUE,
+ nextBinder === res,
+ next
+ ) ELSE zero
- object vpmName {
- val one = newTermName("one")
- val drop = newTermName("drop")
- val flatMap = newTermName("flatMap")
- val get = newTermName("get")
- val guard = newTermName("guard")
- val isEmpty = newTermName("isEmpty")
- val orElse = newTermName("orElse")
- val outer = newTermName("<outer>")
- val runOrElse = newTermName("runOrElse")
- val zero = newTermName("zero")
-
- def counted(str: String, i: Int) = newTermName(str+i)
+ def flatMapGuard(guardTree: Tree, next: Tree): Tree =
+ IF (guardTree) THEN next ELSE zero
}
+ }
- def typesConform(tp: Type, pt: Type) = ((tp eq pt) || (tp <:< pt))
-
- trait CommonCodeGen extends AbsCodeGen { self: CommonCodeGen with MatchingStrategyGen with MonadInstGen =>
- def fun(arg: Symbol, body: Tree): Tree = Function(List(ValDef(arg)), body)
- def genTypeApply(tfun: Tree, args: Type*): Tree = if(args contains NoType) tfun else TypeApply(tfun, args.toList map TypeTree)
- def tupleSel(binder: Symbol)(i: Int): Tree = (REF(binder) DOT nme.productAccessorName(i)) // make tree that accesses the i'th component of the tuple referenced by binder
- def index(tgt: Tree)(i: Int): Tree = tgt APPLY (LIT(i))
- def drop(tgt: Tree)(n: Int): Tree = (tgt DOT vpmName.drop) (LIT(n))
- def _equals(checker: Tree, binder: Symbol): Tree = checker MEMBER_== REF(binder) // NOTE: checker must be the target of the ==, that's the patmat semantics for ya
- def and(a: Tree, b: Tree): Tree = a AND b
- def condOptimized(c: Tree, then: Tree): Tree = IF (c) THEN then ELSE zero
-
- // the force is needed mainly to deal with the GADT typing hack (we can't detect it otherwise as tp nor pt need contain an abstract type, we're just casting wildly)
- def _asInstanceOf(t: Tree, tp: Type, force: Boolean = false): Tree = { val tpX = repackExistential(tp)
- if (!force && (t.tpe ne NoType) && t.isTyped && typesConform(t.tpe, tpX)) t //{ println("warning: emitted redundant asInstanceOf: "+(t, t.tpe, tp)); t } //.setType(tpX)
- else gen.mkAsInstanceOf(t, tpX, true, false)
- }
-
- def _isInstanceOf(b: Symbol, tp: Type): Tree = gen.mkIsInstanceOf(REF(b), repackExistential(tp), true, false)
- // { val tpX = repackExistential(tp)
- // if (typesConform(b.info, tpX)) { println("warning: emitted spurious isInstanceOf: "+(b, tp)); TRUE }
- // else gen.mkIsInstanceOf(REF(b), tpX, true, false)
- // }
-
- def _asInstanceOf(b: Symbol, tp: Type): Tree = { val tpX = repackExistential(tp)
- if (typesConform(b.info, tpX)) REF(b) //{ println("warning: emitted redundant asInstanceOf: "+(b, b.info, tp)); REF(b) } //.setType(tpX)
- else gen.mkAsInstanceOf(REF(b), tpX, true, false)
- }
-
- // duplicated out of frustration with cast generation
- def mkZero(tp: Type): Tree = {
- tp.typeSymbol match {
- case UnitClass => Literal(Constant())
- case BooleanClass => Literal(Constant(false))
- case FloatClass => Literal(Constant(0.0f))
- case DoubleClass => Literal(Constant(0.0d))
- case ByteClass => Literal(Constant(0.toByte))
- case ShortClass => Literal(Constant(0.toShort))
- case IntClass => Literal(Constant(0))
- case LongClass => Literal(Constant(0L))
- case CharClass => Literal(Constant(0.toChar))
- case _ => gen.mkAsInstanceOf(Literal(Constant(null)), tp, any = true, wrapInApply = false) // the magic incantation is true/false here
- }
- }
+ trait MatchOptimizations extends CommonSubconditionElimination
+ with DeadCodeElimination
+ with SwitchEmission
+ with OptimizedCodegen { self: TreeMakers =>
+ override def optimizeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type): (List[List[TreeMaker]], List[Tree]) = {
+ val optCases = doCSE(prevBinder, doDCE(prevBinder, cases, pt), pt)
+ val toHoist = (
+ for (treeMakers <- optCases)
+ yield treeMakers.collect{case tm: ReusedCondTreeMaker => tm.treesToHoist}
+ ).flatten.flatten.toList
+ (optCases, toHoist)
}
-
- def matchingStrategy: Tree
}
}
-
-// object noShadowedUntyped extends Traverser {
-// override def traverse(t: Tree) {
-// if ((t.tpe ne null) && (t.tpe ne NoType)) okTree = t
-// else if(okTree ne null) println("untyped subtree "+ t +" in typed tree"+ okTree +" : "+ okTree.tpe)
-// super.traverse(t)
-// }
-// var okTree: Tree = null
-// }
-// private def c(t: Tree): Tree = noShadowedUntyped(t)
-
- // def approximateTreeMaker(tm: TreeMaker): List[Test] = tm match {
- // case ExtractorTreeMaker(extractor, _, _) => HavocTest
- // case FilteredExtractorTreeMaker(extractor, lenGuard, _, _) => HavocTest
- // case ProductExtractorTreeMaker(testedBinder, lenGuard, _) => TopTest // TODO: (testedBinder ne null) and lenGuard
- //
- // // cond = typeTest(prevBinder, nextBinderTp)
- // // res = pmgen._asInstanceOf(prevBinder, nextBinderTp)
- // case TypeTestTreeMaker(testedBinder, pt, _) =>
- //
- // // cond = typeAndEqualityTest(patBinder, pt)
- // // res = pmgen._asInstanceOf(patBinder, nextBinderTp)
- // case TypeAndEqualityTestTreeMaker(_, testedBinder, pt, _) =>
- //
- // // cond = pmgen._equals(patTree, prevBinder)
- // // res = CODE.REF(prevBinder)
- // case EqualityTestTreeMaker(testedBinder, rhs, _) =>
- //
- // case AlternativesTreeMaker(_, alts: *) =>
- //
- // case GuardTreeMaker(guardTree) =>
- // }
-
- // // TODO: it's not exactly sound to represent an unapply-call by its symbol... also need to consider the prefix, like the outer-test (can this be captured as the path to this test?)
- // type ExtractorRepr = Symbol
- //
- // // TODO: we're undoing tree-construction that we ourselves performed earlier -- how about not-doing so we don't have to undo?
- // private def findBinderArgOfApply(extractor: Tree, unappSym: Symbol): Symbol = {
- // class CollectTreeTraverser[T](pf: PartialFunction[Tree => T]) extends Traverser {
- // val hits = new ListBuffer[T]
- // override def traverse(t: Tree) {
- // if (pf.isDefinedAt(t)) hits += pf(t)
- // super.traverse(t)
- // }
- // }
- // val trav = new CollectTreeTraverser{ case Apply(unapp, List(arg)) if unapp.symbol eq unappSym => arg.symbol}
- // trav.traverse(extractor)
- // trav.hits.headOption getOrElse NoSymbol
- // }
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index a6c2f75d5e..fa4664b34f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -924,9 +924,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
}
def validateVarianceArgs(tps: List[Type], variance: Int, tparams: List[Symbol]) {
- (tps zip tparams) foreach {
- case (tp, tparam) => validateVariance(tp, variance * tparam.variance)
- }
+ foreach2(tps, tparams)((tp, tparam) => validateVariance(tp, variance * tparam.variance))
}
validateVariance(base.info, CoVariance)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index d3ff331f98..bc8a8a31b5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -100,6 +100,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case MethodType(params, _) =>
val argResultsBuff = new ListBuffer[SearchResult]()
val argBuff = new ListBuffer[Tree]()
+ var paramFailed = false
def mkPositionalArg(argTree: Tree, paramName: Name) = argTree
def mkNamedArg(argTree: Tree, paramName: Name) = atPos(argTree.pos)(new AssignOrNamedArg(Ident(paramName), (argTree)))
@@ -114,14 +115,14 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
for(ar <- argResultsBuff)
paramTp = paramTp.subst(ar.subst.from, ar.subst.to)
- val res = inferImplicit(fun, paramTp, true, false, context)
+ val res = if (paramFailed) SearchFailure else inferImplicit(fun, paramTp, context.reportErrors, false, context)
argResultsBuff += res
if (res != SearchFailure) {
argBuff += mkArg(res.tree, param.name)
} else {
mkArg = mkNamedArg // don't pass the default argument (if any) here, but start emitting named arguments for the following args
- if (!param.hasDefault) {
+ if (!param.hasDefault && !paramFailed) {
context.errBuffer.find(_.kind == ErrorKinds.Divergent) match {
case Some(divergentImplicit) =>
// DivergentImplicit error has higher priority than "no implicit found"
@@ -133,6 +134,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case None =>
NoImplicitFoundError(fun, param)
}
+ paramFailed = true
}
/* else {
TODO: alternative (to expose implicit search failure more) -->
@@ -706,8 +708,6 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
}
- def isCodeType(tpe: Type) = tpe.typeSymbol isNonBottomSubClass CodeClass
-
/** Perform the following adaptations of expression, pattern or type `tree` wrt to
* given mode `mode` and given prototype `pt`:
* (-1) For expressions with annotated types, let AnnotationCheckers decide what to do
@@ -767,7 +767,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
withCondConstrTyper(treeInfo.isSelfOrSuperConstrCall(tree)){ typer1 =>
if (original != EmptyTree && pt != WildcardType)
- typer1.silent(tpr => tpr.typed(tpr.applyImplicitArgs(tree), mode, pt)) match {
+ typer1.silent(tpr => {
+ val withImplicitArgs = tpr.applyImplicitArgs(tree)
+ if (tpr.context.hasErrors) tree // silent will wrap it in SilentTypeError anyway
+ else tpr.typed(withImplicitArgs, mode, pt)
+ }) match {
case SilentResultValue(result) =>
result
case _ =>
@@ -1987,8 +1991,6 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
*/
def typedFunction(fun: Function, mode: Int, pt: Type): Tree = {
val numVparams = fun.vparams.length
- val codeExpected = !forMSIL && (pt.typeSymbol isNonBottomSubClass CodeClass)
-
if (numVparams > definitions.MaxFunctionArity)
return MaxFunctionArityError(fun)
@@ -2005,7 +2007,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
else
(FunctionClass(numVparams), fun.vparams map (x => NoType), WildcardType)
- val (clazz, argpts, respt) = decompose(if (codeExpected) pt.normalize.typeArgs.head else pt)
+ val (clazz, argpts, respt) = decompose(pt)
if (argpts.lengthCompare(numVparams) != 0)
WrongNumberOfParametersError(fun, argpts)
else {
@@ -2015,7 +2017,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (isFullyDefined(argpt)) argpt
else {
fun match {
- case etaExpansion(vparams, fn, args) if !codeExpected =>
+ case etaExpansion(vparams, fn, args) =>
silent(_.typed(fn, forFunMode(mode), pt)) match {
case SilentResultValue(fn1) if context.undetparams.isEmpty =>
// if context,undetparams is not empty, the function was polymorphic,
@@ -2047,13 +2049,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val restpe = packedType(body1, fun.symbol).deconst.resultType
val funtpe = typeRef(clazz.tpe.prefix, clazz, formals :+ restpe)
// body = checkNoEscaping.locals(context.scope, restpe, body)
- val fun1 = treeCopy.Function(fun, vparams, body1).setType(funtpe)
- if (codeExpected) lifted(fun1) else fun1
- }
+ treeCopy.Function(fun, vparams, body1).setType(funtpe)
}
-
- def lifted(tree: Tree): Tree = typedPos(tree.pos) {
- Apply(Select(Ident(CodeModule), nme.lift_), List(tree))
}
def typedRefinement(stats: List[Tree]) {
@@ -2915,7 +2912,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
existentialAbstraction(captured.toList, tpe)
}
- /** convert skolems to existentials */
+ /** convert local symbols and skolems to existentials */
def packedType(tree: Tree, owner: Symbol): Type = {
def defines(tree: Tree, sym: Symbol) =
sym.isExistentialSkolem && sym.unpackLocation == tree ||
@@ -3297,7 +3294,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val owntype = elimAnonymousClass(owntype0)
if (needAdapt) cases1 = cases1 map (adaptCase(_, owntype))
- (new MatchTranslator(this)).translateMatch(selector1, cases1, owntype) match {
+ (MatchTranslator(this)).translateMatch(selector1, cases1, owntype) match {
case Block(vd :: Nil, tree@Match(selector, cases)) =>
val selector1 = checkDead(typed(selector, EXPRmode | BYVALmode, WildcardType))
var cases1 = typedCases(tree, cases, packCaptured(selector1.tpe.widen), pt)
@@ -3717,7 +3714,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
return typed(treeCopy.Select(tree, qual1, name), mode, pt)
}
if (!reallyExists(sym)) {
- if (context.owner.toplevelClass.isJavaDefined && name.isTypeName) {
+ if (context.owner.enclosingTopLevelClass.isJavaDefined && name.isTypeName) {
val tree1 = atPos(tree.pos) { gen.convertToSelectFromType(qual, name) }
if (tree1 != EmptyTree) return typed1(tree1, mode, pt)
}
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java b/src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java
index 8b0338ed29..d4c5417260 100644
--- a/src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JExtendedCode.java
@@ -596,6 +596,16 @@ public class JExtendedCode extends JCode {
double minDensity) {
assert keys.length == branches.length;
+ //The special case for empty keys. It makes sense to allow
+ //empty keys and generate LOOKUPSWITCH with defaultBranch
+ //only. This is exactly what javac does for switch statement
+ //that has only a default case.
+ if (keys.length == 0) {
+ emitLOOKUPSWITCH(keys, branches, defaultBranch);
+ return;
+ }
+ //the rest of the code assumes that keys.length > 0
+
// sorting the tables
// FIXME use quicksort
for (int i = 1; i < keys.length; i++) {
diff --git a/src/intellij/scala-lang.ipr.SAMPLE b/src/intellij/scala-lang.ipr.SAMPLE
index 4d32f0e2e1..93b6285cfb 100644
--- a/src/intellij/scala-lang.ipr.SAMPLE
+++ b/src/intellij/scala-lang.ipr.SAMPLE
@@ -32,7 +32,7 @@
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
<component name="EntryPointsManager">
<entry_points version="2.0" />
- </component>
+ </component>
<component name="InspectionProjectProfileManager">
<profiles>
<profile version="1.0" is_locked="false">
@@ -201,6 +201,7 @@
<module fileurl="file://$PROJECT_DIR$/library.iml" filepath="$PROJECT_DIR$/library.iml" />
<module fileurl="file://$PROJECT_DIR$/manual.iml" filepath="$PROJECT_DIR$/manual.iml" />
<module fileurl="file://$PROJECT_DIR$/partest.iml" filepath="$PROJECT_DIR$/partest.iml" />
+ <module fileurl="file://$PROJECT_DIR$/scala.iml" filepath="$PROJECT_DIR$/scala.iml" />
<module fileurl="file://$PROJECT_DIR$/scalap.iml" filepath="$PROJECT_DIR$/scalap.iml" />
<module fileurl="file://$PROJECT_DIR$/swing.iml" filepath="$PROJECT_DIR$/swing.iml" />
</modules>
diff --git a/src/intellij/scala.iml.SAMPLE b/src/intellij/scala.iml.SAMPLE
new file mode 100644
index 0000000000..8ea9d0dd71
--- /dev/null
+++ b/src/intellij/scala.iml.SAMPLE
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
+ <exclude-output />
+ <content url="file://$MODULE_DIR$/../.." />
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ </component>
+</module>
+
diff --git a/src/library/scala/MatchingStrategy.scala b/src/library/scala/MatchingStrategy.scala
deleted file mode 100644
index d11598bad6..0000000000
--- a/src/library/scala/MatchingStrategy.scala
+++ /dev/null
@@ -1,27 +0,0 @@
-package scala
-
-abstract class MatchingStrategy[M[+x]] {
- // runs the matcher on the given input
- def runOrElse[T, U](in: T)(matcher: T => M[U]): U
-
- def zero: M[Nothing]
- def one[T](x: T): M[T]
- def guard[T](cond: Boolean, then: => T): M[T]
- def isSuccess[T, U](x: T)(f: T => M[U]): Boolean // used for isDefinedAt
-
- def caseResult[T](x: T): M[T] = one(x) // used as a marker to distinguish the RHS of a case (case pat => RHS) and intermediate successes
- // when deriving a partial function from a pattern match,
- // we need to distinguish the RHS of a case, which should not be evaluated when computing isDefinedAt,
- // from an intermediate result (which must be computed)
-}
-
-object MatchingStrategy {
- implicit object OptionMatchingStrategy extends MatchingStrategy[Option] {
- type M[+x] = Option[x]
- @inline def runOrElse[T, U](x: T)(f: T => M[U]): U = f(x) getOrElse (throw new MatchError(x))
- @inline def zero: M[Nothing] = None
- @inline def one[T](x: T): M[T] = Some(x)
- @inline def guard[T](cond: Boolean, then: => T): M[T] = if(cond) Some(then) else None
- @inline def isSuccess[T, U](x: T)(f: T => M[U]): Boolean = !f(x).isEmpty
- }
-} \ No newline at end of file
diff --git a/src/library/scala/collection/IndexedSeqOptimized.scala b/src/library/scala/collection/IndexedSeqOptimized.scala
index e2541f2a66..196e77c91b 100755
--- a/src/library/scala/collection/IndexedSeqOptimized.scala
+++ b/src/library/scala/collection/IndexedSeqOptimized.scala
@@ -104,7 +104,7 @@ trait IndexedSeqOptimized[+A, +Repr] extends IndexedSeqLike[A, Repr] { self =>
override /*IterableLike*/
def slice(from: Int, until: Int): Repr = {
val lo = math.max(from, 0)
- val hi = math.min(until, length)
+ val hi = math.min(math.max(until, 0), length)
val elems = math.max(hi - lo, 0)
val b = newBuilder
b.sizeHint(elems)
diff --git a/src/library/scala/math/BigDecimal.scala b/src/library/scala/math/BigDecimal.scala
index 497de92c80..c1f45eccfb 100644
--- a/src/library/scala/math/BigDecimal.scala
+++ b/src/library/scala/math/BigDecimal.scala
@@ -33,8 +33,10 @@ object BigDecimal {
/** Cache ony for defaultMathContext using BigDecimals in a small range. */
private lazy val cache = new Array[BigDecimal](maxCached - minCached + 1)
- object RoundingMode extends Enumeration(java.math.RoundingMode.values map (_.toString) : _*) with Serializable {
+ object RoundingMode extends Enumeration {
type RoundingMode = Value
+ // These are supposed to be the same as java.math.RoundingMode.values,
+ // though it seems unwise to rely on the correspondence.
val UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_DOWN, HALF_EVEN, UNNECESSARY = Value
}
diff --git a/src/library/scala/reflect/Code.scala b/src/library/scala/reflect/Code.scala
index 52705d302c..f28264c7a2 100644
--- a/src/library/scala/reflect/Code.scala
+++ b/src/library/scala/reflect/Code.scala
@@ -11,12 +11,14 @@
package scala.reflect
/** This type is required by the compiler and <b>should not be used in client code</b>. */
+@deprecated("Replaced with scala.reflect.macro.Context#reify, will be completely removed soon", "2.10")
class Code[T: Manifest](val tree: scala.reflect.mirror.Tree) {
val manifest = implicitly[Manifest[T]]
override def toString = "Code(tree = "+tree+", manifest = "+manifest+")"
}
/** This type is required by the compiler and <b>should not be used in client code</b>. */
+@deprecated("Replaced with scala.reflect.macro.Context#reify, will be completely removed soon", "2.10")
object Code {
def lift[A](tree: A): Code[A] =
throw new Error("Code was not lifted by compiler")
diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala
index 8bd45c0e33..6c02878b19 100644
--- a/src/library/scala/reflect/Manifest.scala
+++ b/src/library/scala/reflect/Manifest.scala
@@ -222,7 +222,7 @@ object Manifest {
val clazz = classToSymbol(erasure)
val pre = prefix match {
case Some(pm) => pm.tpe
- case None => clazz.owner.thisType
+ case None => clazz.owner.thisPrefix
}
namedType(pre, clazz, typeArguments map (_.tpe))
}
diff --git a/src/library/scala/reflect/api/Mirror.scala b/src/library/scala/reflect/api/Mirror.scala
index 136f52b05f..448dca752c 100644
--- a/src/library/scala/reflect/api/Mirror.scala
+++ b/src/library/scala/reflect/api/Mirror.scala
@@ -3,57 +3,59 @@ package api
/** A mirror establishes connections of
* runtime entities such as class names and object instances
- * with a refexive universe.
+ * with a reflexive universe.
*/
trait Mirror extends Universe with RuntimeTypes with TreeBuildUtil {
/** The Scala class symbol that has given fully qualified name
* @param name The fully qualified name of the class to be returned
- * @throws java.lang.ClassNotFoundException if no class wiht that name exists
+ * @throws java.lang.ClassNotFoundException if no class with that name exists
* to do: throws anything else?
*/
- def classWithName(name: String): Symbol
+ def symbolForName(name: String): Symbol
- /** Return a reference to the companion object of this class symbol
+ /** Return a reference to the companion object of the given class symbol.
*/
- def getCompanionObject(clazz: Symbol): AnyRef
+ def companionInstance(clazz: Symbol): AnyRef
- /** The Scala class symbol corresponding to the runtime class of given object
- * @param The object from which the class is returned
+ /** The Scala class symbol corresponding to the runtime class of the given instance.
+ * @param instance The instance
+ * @return The class Symbol for the instance
* @throws ?
*/
- def getClass(obj: AnyRef): Symbol
+ def symbolOfInstance(instance: Any): Symbol
- /** The Scala type corresponding to the runtime type of given object.
+ /** The Scala type corresponding to the runtime type of given instance.
* If the underlying class is parameterized, this will be an existential type,
* with unknown type arguments.
*
- * @param The object from which the type is returned
+ * @param instance The instance.
+ * @return The Type of the given instance.
* @throws ?
*/
- def getType(obj: AnyRef): Type
+ def typeOfInstance(instance: Any): Type
/** The value of a field on a receiver instance.
* @param receiver The receiver instance
* @param field The field
* @return The value contained in `receiver.field`.
*/
- def getValue(receiver: AnyRef, field: Symbol): Any
+ def getValueOfField(receiver: AnyRef, field: Symbol): Any
/** Sets the value of a field on a receiver instance.
* @param receiver The receiver instance
* @param field The field
* @param value The new value to be stored in the field.
*/
- def setValue(receiver: AnyRef, field: Symbol, value: Any): Unit
+ def setValueOfField(receiver: AnyRef, field: Symbol, value: Any): Unit
- /** Invokes a method on a reciver instance with some arguments
+ /** Invokes a method on a receiver instance with some arguments
* @param receiver The receiver instance
* @param meth The method
* @param args The method call's arguments
* @return The result of invoking `receiver.meth(args)`
*/
- def invoke(receiver: AnyRef, meth: Symbol, args: Any*): Any
+ def invoke(receiver: AnyRef, meth: Symbol)(args: Any*): Any
/** Maps a Java class to a Scala type reference
* @param clazz The Java class object
diff --git a/src/library/scala/reflect/api/Modifier.scala b/src/library/scala/reflect/api/Modifier.scala
index 8569b103cf..c0123ed955 100644
--- a/src/library/scala/reflect/api/Modifier.scala
+++ b/src/library/scala/reflect/api/Modifier.scala
@@ -1,11 +1,82 @@
package scala.reflect.api
-object Modifier extends Enumeration {
+import collection.{ immutable, mutable }
- val `protected`, `private`, `override`, `abstract`, `final`,
- `sealed`, `implicit`, `lazy`, `macro`, `case`, `trait`,
- deferred, interface, mutable, parameter, covariant, contravariant,
- preSuper, abstractOverride, local, java, static, caseAccessor,
- defaultParameter, defaultInit, paramAccessor, bynameParameter = Value
+sealed abstract class Modifier {
+ def name: String
+ def isKeyword: Boolean
+ def sourceString: String = if (isKeyword) "`" + name + "`" else name
+ override def equals(that: Any) = this eq that.asInstanceOf[AnyRef]
+ override def hashCode = name.hashCode
+ override def toString = name
+}
+final class SymbolModifier private (val name: String, val isKeyword: Boolean) extends Modifier {
+ def this(name: String) = this(name, false)
+}
+final class SourceModifier private (val name: String) extends Modifier {
+ def isKeyword = true
+}
+
+object SymbolModifier {
+ private val seen = mutable.ListBuffer[SymbolModifier]()
+ private[api] def apply(name: String): SymbolModifier = {
+ val mod = name match {
+ case "case" | "trait" => new SymbolModifier(name, isKeyword = true)
+ case _ => new SymbolModifier(name)
+ }
+ seen += mod
+ mod
+ }
+ private[api] def all = seen.toList
+}
+object SourceModifier {
+ private val seen = mutable.ListBuffer[SourceModifier]()
+ private[api] def apply(name: String): SourceModifier = {
+ val mod = new SourceModifier(name)
+ seen += mod
+ mod
+ }
+ private[api] def all = seen.toList
+}
+
+object Modifier extends immutable.Set[Modifier] {
+ val `abstract` = SourceModifier("abstract")
+ val `final` = SourceModifier("final")
+ val `implicit` = SourceModifier("implicit")
+ val `lazy` = SourceModifier("lazy")
+ val `macro` = SourceModifier("macro")
+ val `override` = SourceModifier("override")
+ val `private` = SourceModifier("private")
+ val `protected` = SourceModifier("protected")
+ val `sealed` = SourceModifier("sealed")
+
+ val `case` = SymbolModifier("case")
+ val `trait` = SymbolModifier("trait")
+ val abstractOverride = SymbolModifier("abstractOverride")
+ val bynameParameter = SymbolModifier("bynameParameter")
+ val caseAccessor = SymbolModifier("caseAccessor")
+ val contravariant = SymbolModifier("contravariant")
+ val covariant = SymbolModifier("covariant")
+ val defaultInit = SymbolModifier("defaultInit")
+ val defaultParameter = SymbolModifier("defaultParameter")
+ val deferred = SymbolModifier("deferred")
+ val interface = SymbolModifier("interface")
+ val java = SymbolModifier("java")
+ val local = SymbolModifier("local")
+ val mutable = SymbolModifier("mutable")
+ val paramAccessor = SymbolModifier("paramAccessor")
+ val parameter = SymbolModifier("parameter")
+ val preSuper = SymbolModifier("preSuper")
+ val static = SymbolModifier("static")
+
+ val sourceModifiers: Set[SourceModifier] = SourceModifier.all.toSet
+ val symbolModifiers: Set[SymbolModifier] = SymbolModifier.all.toSet
+ val allModifiers: Set[Modifier] = sourceModifiers ++ symbolModifiers
+ def values = allModifiers
+
+ def contains(key: Modifier) = allModifiers(key)
+ def iterator = allModifiers.iterator
+ def -(elem: Modifier) = allModifiers - elem
+ def +(elem: Modifier) = allModifiers + elem
}
diff --git a/src/library/scala/reflect/api/Names.scala b/src/library/scala/reflect/api/Names.scala
index 9498f0af36..3a00f21c8c 100755
--- a/src/library/scala/reflect/api/Names.scala
+++ b/src/library/scala/reflect/api/Names.scala
@@ -11,7 +11,6 @@ package api
* `name1 == name2` implies `name1 eq name2`.
*/
trait Names {
-
/** The abstract type of names */
type Name >: Null <: AbsName
@@ -37,12 +36,20 @@ trait Names {
/** Replaces all occurrences of $op_names in this name by corresponding operator symbols.
* Example: `foo_+=` becomes `foo_$plus$eq`.
*/
- def decode: String
+ def decoded: String
/** Replaces all occurrences of operator symbols in this name by corresponding $op_names.
* Example: `foo_$plus$eq` becomes `foo_+=`
*/
- def encode: Name
+ def encoded: String
+
+ /** The decoded name, still represented as a name.
+ */
+ def decodedName: Name
+
+ /** The encoded name, still represented as a name.
+ */
+ def encodedName: Name
}
/** Create a new term name.
diff --git a/src/library/scala/reflect/api/StandardDefinitions.scala b/src/library/scala/reflect/api/StandardDefinitions.scala
index 08071660a2..e737b0ea4f 100755
--- a/src/library/scala/reflect/api/StandardDefinitions.scala
+++ b/src/library/scala/reflect/api/StandardDefinitions.scala
@@ -11,14 +11,11 @@ trait StandardDefinitions { self: Universe =>
val definitions: AbsDefinitions
abstract class AbsDefinitions {
- // outer packages and their classes
+ // packages
def RootPackage: Symbol
def RootClass: Symbol
def EmptyPackage: Symbol
- def EmptyPackageClass: Symbol
-
def ScalaPackage: Symbol
- def ScalaPackageClass: Symbol
// top types
def AnyClass : Symbol
@@ -46,20 +43,27 @@ trait StandardDefinitions { self: Universe =>
def StringClass : Symbol
def ClassClass : Symbol
+ // product, tuple, function
+ def TupleClass : Array[Symbol]
+ def ProductClass : Array[Symbol]
+ def FunctionClass : Array[Symbol]
+
// fundamental modules
def PredefModule: Symbol
- // fundamental type constructions
- def ClassType(arg: Type): Type
+ /** Given a type T, returns the type corresponding to the VM's
+ * representation: ClassClass's type constructor applied to `arg`.
+ */
+ def vmClassType(arg: Type): Type // !!! better name?
/** The string representation used by the given type in the VM.
*/
- def signature(tp: Type): String
+ def vmSignature(sym: Symbol, info: Type): String
/** Is symbol one of the value classes? */
- def isValueClass(sym: Symbol): Boolean
+ def isValueClass(sym: Symbol): Boolean // !!! better name?
/** Is symbol one of the numeric value classes? */
- def isNumericValueClass(sym: Symbol): Boolean
+ def isNumericValueClass(sym: Symbol): Boolean // !!! better name?
}
}
diff --git a/src/library/scala/reflect/api/StandardNames.scala b/src/library/scala/reflect/api/StandardNames.scala
new file mode 100644
index 0000000000..81517d2a6b
--- /dev/null
+++ b/src/library/scala/reflect/api/StandardNames.scala
@@ -0,0 +1,21 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package api
+
+trait StandardNames { self: Universe =>
+
+ val nme: AbsTermNames
+
+ abstract class AbsTermNames {
+ val CONSTRUCTOR: TermName
+ }
+
+ val tpnme: AbsTypeNames
+
+ abstract class AbsTypeNames {
+ }
+}
diff --git a/src/library/scala/reflect/api/Symbols.scala b/src/library/scala/reflect/api/Symbols.scala
index 01c1a0f2ae..15d754b5b4 100755
--- a/src/library/scala/reflect/api/Symbols.scala
+++ b/src/library/scala/reflect/api/Symbols.scala
@@ -9,11 +9,20 @@ trait Symbols { self: Universe =>
/** The modifiers of this symbol
*/
- def allModifiers: Set[Modifier.Value]
+ def modifiers: Set[Modifier]
/** Does this symbol have given modifier?
*/
- def hasModifier(mod: Modifier.Value): Boolean
+ def hasModifier(mod: Modifier): Boolean
+
+ /** A list of annotations attached to this Symbol.
+ */
+ def annotations: List[self.AnnotationInfo]
+
+ /** Whether this symbol carries an annotation for which the given
+ * symbol is its typeSymbol.
+ */
+ def hasAnnotation(sym: Symbol): Boolean
/** The owner of this symbol. This is the symbol
* that directly contains the current symbol's definition.
@@ -30,14 +39,6 @@ trait Symbols { self: Universe =>
*/
def name: Name
- /** The name of the symbol before decoding, e.g. `\$eq\$eq` instead of `==`.
- */
- def encodedName: String
-
- /** The decoded name of the symbol, e.g. `==` instead of `\$eq\$eq`.
- */
- def decodedName: String
-
/** The encoded full path name of this symbol, where outer names and inner names
* are separated by periods.
*/
@@ -66,49 +67,43 @@ trait Symbols { self: Universe =>
*
* The java access levels translate as follows:
*
- * java private: hasFlag(PRIVATE) && !hasAccessBoundary
- * java package: !hasFlag(PRIVATE | PROTECTED) && (privateWithin == enclosing package)
- * java protected: hasFlag(PROTECTED) && (privateWithin == enclosing package)
- * java public: !hasFlag(PRIVATE | PROTECTED) && !hasAccessBoundary
+ * java private: hasFlag(PRIVATE) && (privateWithin == NoSymbol)
+ * java package: !hasFlag(PRIVATE | PROTECTED) && (privateWithin == enclosingPackage)
+ * java protected: hasFlag(PROTECTED) && (privateWithin == enclosingPackage)
+ * java public: !hasFlag(PRIVATE | PROTECTED) && (privateWithin == NoSymbol)
*/
def privateWithin: Symbol
- /** Whether this symbol has a "privateWithin" visibility barrier attached.
- */
- def hasAccessBoundary: Boolean
-
- /** A list of annotations attached to this Symbol.
- */
- def annotations: List[self.AnnotationInfo]
-
/** For a class: the module or case class factory with the same name in the same package.
+ * For a module: the class with the same name in the same package.
* For all others: NoSymbol
*/
- def companionModule: Symbol
-
- /** For a module: the class with the same name in the same package.
- * For all others: NoSymbol
- */
- def companionClass: Symbol
-
- /** The module corresponding to this module class (note that this
- * is not updated when a module is cloned), or NoSymbol if this is not a ModuleClass
- */
- def sourceModule: Symbol
+ def companionSymbol: Symbol
/** If symbol is an object definition, its implied associated class,
* otherwise NoSymbol
*/
def moduleClass: Symbol // needed for LiftCode
- /** The top-level class containing this symbol. */
- def toplevelClass: Symbol
+ /** If this symbol is a top-level class, this symbol; otherwise the next enclosing
+ * top-level class, or `NoSymbol` if none exists.
+ */
+ def enclosingTopLevelClass: Symbol
- /** The next enclosing class, or `NoSymbol` if none exists */
- def enclClass : Symbol
+ /** If this symbol is a class, this symbol; otherwise the next enclosing
+ * class, or `NoSymbol` if none exists.
+ */
+ def enclosingClass: Symbol
- /** The next enclosing method, or `NoSymbol` if none exists */
- def enclMethod : Symbol
+ /** If this symbol is a method, this symbol; otherwise the next enclosing
+ * method, or `NoSymbol` if none exists.
+ */
+ def enclosingMethod: Symbol
+
+ /** If this symbol is a package class, this symbol; otherwise the next enclosing
+ * package class, or `NoSymbol` if none exists.
+ */
+ def enclosingPackageClass: Symbol
/** Does this symbol represent the definition of term?
* Note that every symbol is either a term or a type.
@@ -141,13 +136,13 @@ trait Symbols { self: Universe =>
/** The type signature of this symbol.
* Note if the symbol is a member of a class, one almost always is interested
- * in `typeSigIn` with a site type instead.
+ * in `typeSignatureIn` with a site type instead.
*/
- def typeSig: Type
+ def typeSignature: Type // !!! Since one should almost never use this, let's give it a different name.
/** The type signature of this symbol seen as a member of given type `site`.
*/
- def typeSigIn(site: Type): Type
+ def typeSignatureIn(site: Type): Type
/** A type reference that refers to this type symbol
* Note if symbol is a member of a class, one almost always is interested
@@ -156,11 +151,11 @@ trait Symbols { self: Universe =>
* Example: Given a class declaration `class C[T] { ... } `, that generates a symbol
* `C`. Then `C.asType` is the type `C[T]`.
*
- * By contrast, `C.typeSig` would be a type signature of form
+ * By contrast, `C.typeSignature` would be a type signature of form
* `PolyType(ClassInfoType(...))` that describes type parameters, value
* parameters, parent types, and members of `C`.
*/
- def asType: Type
+ def asType: Type // !!! Same as typeSignature.
/** A type reference that refers to this type symbol seen
* as a member of given type `site`.
@@ -172,37 +167,37 @@ trait Symbols { self: Universe =>
* are part of results of `asType`, but not of `asTypeConstructor`.
*
* Example: Given a class declaration `class C[T] { ... } `, that generates a symbol
- * `C`. Then `C.asType` is the type `C[T]`, but `C.asTypeCponstructor` is `C`.
+ * `C`. Then `C.asType` is the type `C[T]`, but `C.asTypeConstructor` is `C`.
*/
def asTypeConstructor: Type // needed by LiftCode
+
+ /** If this symbol is a class, the type `C.this`, otherwise `NoPrefix`.
+ */
+ def thisPrefix: Type
/** If this symbol is a class or trait, its self type, otherwise the type
* of the symbol itself.
*/
- def typeOfThis: Type
-
- /** If this symbol is a class, the type `C.this`, otherwise `NoPrefix`.
- */
- def thisType: Type
+ def selfType: Type
/** A fresh symbol with given name `name`, position `pos` and flags `flags` that has
* the current symbol as its owner.
*/
def newNestedSymbol(name: Name, pos: Position, flags: Long): Symbol // needed by LiftCode
-
+
/** Low-level operation to set the symbol's flags
* @return the symbol itself
*/
- def setInternalFlags(flags: Long): this.type // needed by LiftCode
+ def setInternalFlags(flags: Long): this.type // needed by LiftCode !!! not enough reason to have in the api
/** Set symbol's type signature to given type
* @return the symbol itself
*/
- def setTypeSig(tpe: Type): this.type // needed by LiftCode
+ def setTypeSignature(tpe: Type): this.type // needed by LiftCode !!! not enough reason to have in the api
/** Set symbol's annotations to given annotations `annots`.
*/
- def setAnnotations(annots: AnnotationInfo*): this.type // needed by LiftCode
+ def setAnnotations(annots: AnnotationInfo*): this.type // needed by LiftCode !!! not enough reason to have in the api
}
val NoSymbol: Symbol
diff --git a/src/library/scala/reflect/api/TreeBuildUtil.scala b/src/library/scala/reflect/api/TreeBuildUtil.scala
index b437824925..f28008bc21 100644
--- a/src/library/scala/reflect/api/TreeBuildUtil.scala
+++ b/src/library/scala/reflect/api/TreeBuildUtil.scala
@@ -3,19 +3,19 @@ package scala.reflect.api
trait TreeBuildUtil extends Universe {
/** The symbol corresponding to the globally accessible class with the
- * given fully qualified name `fullname`.
+ * given fully qualified name `fullName`.
*/
- def staticClass(fullname: String): Symbol
+ def staticClass(fullName: String): Symbol
/** The symbol corresponding to the globally accessible object with the
- * given fully qualified name `fullname`.
+ * given fully qualified name `fullName`.
*/
- def staticModule(fullname: String): Symbol
+ def staticModule(fullName: String): Symbol
/** The this-ptype of the globally accessible object with the
- * given fully qualified name `fullname`.
+ * given fully qualified name `fullName`.
*/
- def thisModuleType(fullname: String): Type
+ def thisModuleType(fullName: String): Type
/** Selects type symbol with given simple name `name` from the defined members of `owner`.
*/
@@ -38,7 +38,7 @@ trait TreeBuildUtil extends Universe {
* @param tsig the type signature of the free variable
* @param value the value of the free variable at runtime
*/
- def freeVar(name: String, tsig: Type, value: Any): Symbol
+ def newFreeVar(name: String, info: Type, value: Any): Symbol
/** Create a Modiiers structure given internal flags, qualifier, annotations */
def modifiersFromInternalFlags(flags: Long, privateWithin: Name, annotations: List[Tree]): Modifiers
diff --git a/src/library/scala/reflect/api/TreePrinters.scala b/src/library/scala/reflect/api/TreePrinters.scala
index 88ef450ed9..19bfd09b81 100644
--- a/src/library/scala/reflect/api/TreePrinters.scala
+++ b/src/library/scala/reflect/api/TreePrinters.scala
@@ -31,18 +31,6 @@ trait TreePrinters { self: Universe =>
// emits more or less verbatim representation of the provided tree
// todo. when LiftCode becomes a macro, throw this code away and use that macro
class RawTreePrinter(out: PrintWriter) extends TreePrinter {
- import scala.reflect.api.Modifier
- import scala.reflect.api.Modifier._
-
- def copypasteModifier(mod: Modifier.Value): String = mod match {
- case mod @ (
- `protected` | `private` | `override` |
- `abstract` | `final` | `sealed` |
- `implicit` | `lazy` | `macro` |
- `case` | `trait`) => "`" + mod.toString + "`"
- case mod => mod.toString
- }
-
def print(args: Any*): Unit = args foreach {
case EmptyTree =>
print("EmptyTree")
@@ -77,14 +65,14 @@ trait TreePrinters { self: Universe =>
print(")")
case mods: Modifiers =>
val parts = collection.mutable.ListBuffer[String]()
- parts += "Set(" + mods.allModifiers.map{copypasteModifier}.mkString(", ") + ")"
+ parts += "Set(" + mods.modifiers.map(_.sourceString).mkString(", ") + ")"
parts += "newTypeName(\"" + mods.privateWithin.toString + "\")"
parts += "List(" + mods.annotations.map{showRaw}.mkString(", ") + ")"
var keep = 3
if (keep == 3 && mods.annotations.isEmpty) keep -= 1
if (keep == 2 && mods.privateWithin == EmptyTypeName) keep -= 1
- if (keep == 1 && mods.allModifiers.isEmpty) keep -= 1
+ if (keep == 1 && mods.modifiers.isEmpty) keep -= 1
print("Modifiers(", parts.take(keep).mkString(", "), ")")
case name: Name =>
diff --git a/src/library/scala/reflect/api/Trees.scala b/src/library/scala/reflect/api/Trees.scala
index 03b043c188..32940cbcd6 100644
--- a/src/library/scala/reflect/api/Trees.scala
+++ b/src/library/scala/reflect/api/Trees.scala
@@ -16,14 +16,14 @@ trait Trees { self: Universe =>
type Modifiers <: AbsModifiers
abstract class AbsModifiers {
- def hasModifier(mod: Modifier.Value): Boolean
- def allModifiers: Set[Modifier.Value]
+ def modifiers: Set[Modifier]
+ def hasModifier(mod: Modifier): Boolean
def privateWithin: Name // default: EmptyTypeName
def annotations: List[Tree] // default: List()
def mapAnnotations(f: List[Tree] => List[Tree]): Modifiers
}
- def Modifiers(mods: Set[Modifier.Value] = Set(),
+ def Modifiers(mods: Set[Modifier] = Set(),
privateWithin: Name = EmptyTypeName,
annotations: List[Tree] = List()): Modifiers
@@ -476,6 +476,17 @@ trait Trees { self: Universe =>
*/
case class New(tpt: Tree) extends TermTree
+ /** 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 = {
+ assert(!argss.isEmpty)
+ // todo. we need to expose names in scala.reflect.api
+// val superRef: Tree = Select(New(tpt), nme.CONSTRUCTOR)
+ val superRef: Tree = Select(New(tpt), nme.CONSTRUCTOR)
+ (superRef /: argss) (Apply)
+ }
+
/** Type annotation, eliminated by explicit outer */
case class Typed(expr: Tree, tpt: Tree)
extends TermTree
@@ -537,6 +548,9 @@ trait Trees { self: Universe =>
// The symbol of a This is the class to which the this refers.
// For instance in C.this, it would be C.
+ def This(sym: Symbol): Tree =
+ This(sym.name.toTypeName) setSymbol sym
+
/** Designator <qualifier> . <name> */
case class Select(qualifier: Tree, name: Name)
extends RefTree
@@ -629,10 +643,10 @@ trait Trees { self: Universe =>
}
def TypeTree(tp: Type): TypeTree = TypeTree() setType tp
-
+
/** An empty deferred value definition corresponding to:
* val _: _
- * This is used as a placeholder in the `self` parameter Template if there is
+ * This is used as a placeholder in the `self` parameter Template if there is
* no definition of a self value of self type.
*/
def emptyValDef: ValDef
@@ -1126,9 +1140,9 @@ trait Trees { self: Universe =>
abstract class Transformer {
val treeCopy: TreeCopier = newLazyTreeCopier
protected var currentOwner: Symbol = definitions.RootClass
- protected def currentMethod = currentOwner.enclMethod
- protected def currentClass = currentOwner.enclClass
- protected def currentPackage = currentOwner.toplevelClass.owner
+ protected def currentMethod = currentOwner.enclosingMethod
+ protected def currentClass = currentOwner.enclosingClass
+ protected def currentPackage = currentOwner.enclosingTopLevelClass.owner
def transform(tree: Tree): Tree = tree match {
case EmptyTree =>
tree
diff --git a/src/library/scala/reflect/api/Types.scala b/src/library/scala/reflect/api/Types.scala
index 6185a788ae..8a91956320 100755
--- a/src/library/scala/reflect/api/Types.scala
+++ b/src/library/scala/reflect/api/Types.scala
@@ -6,7 +6,6 @@ trait Types { self: Universe =>
/** This class declares operations that are visible in a Type.
*/
abstract class AbsType {
-
/** The type symbol associated with the type, or `NoSymbol` for types
* that do not refer to a type symbol.
*/
@@ -47,7 +46,7 @@ trait Types { self: Universe =>
/** Substitute types in `to` for corresponding occurrences of references to
* symbols `from` in this type.
*/
- def subst(from: List[Symbol], to: List[Type]): Type
+ def substituteTypes(from: List[Symbol], to: List[Type]): Type // !!! Too many things with names like "subst"
/** If this is a parameterized types, the type arguments.
* Otherwise the empty list
@@ -56,7 +55,7 @@ trait Types { self: Universe =>
/** Is this type a type constructor that is missing its type arguments?
*/
- def isHigherKinded: Boolean
+ def isHigherKinded: Boolean // !!! This should be called "isTypeConstructor", no?
/**
* Expands type aliases and converts higher-kinded TypeRefs to PolyTypes.
@@ -66,7 +65,7 @@ trait Types { self: Universe =>
* TypeRef(pre, <List>, List()) is replaced by
* PolyType(X, TypeRef(pre, <List>, List(X)))
*/
- def normalize: Type
+ def normalize: Type // !!! Alternative name? "normalize" is used to mean too many things.
/** Does this type conform to given type argument `that`? */
def <:< (that: Type): Boolean
@@ -74,11 +73,11 @@ trait Types { self: Universe =>
/** Is this type equivalent to given type argument `that`? */
def =:= (that: Type): Boolean
- /** The list of all baseclasses of this type (including its own typeSymbol)
+ /** The list of all base classes of this type (including its own typeSymbol)
* in reverse linearization order, starting with the class itself and ending
* in class Any.
*/
- def baseClasses: List[Symbol]
+ def baseClasses: List[Symbol] // !!! Alternative name, perhaps linearization?
/** The least type instance of given class which is a supertype
* of this type. Example:
@@ -104,9 +103,9 @@ trait Types { self: Universe =>
def asSeenFrom(pre: Type, clazz: Symbol): Type
/** The erased type corresponding to this type after
- * all transcformations from Scala to Java have been performed.
+ * all transformations from Scala to Java have been performed.
*/
- def erasedType: Type
+ def erasedType: Type // !!! "erasedType", compare with "widen" (so "erase") or "underlying" (so "erased")
/** Apply `f` to each part of this type, returning
* a new type. children get mapped before their parents */
@@ -138,7 +137,7 @@ trait Types { self: Universe =>
/** If this is a singleton type, widen it to its nearest underlying non-singleton
* base type by applying one or more `underlying` dereferences.
- * If this is not a singlecon type, returns this type itself.
+ * If this is not a singleton type, returns this type itself.
*
* Example:
*
@@ -400,11 +399,6 @@ trait Types { self: Universe =>
def unapply(tpe: ClassInfoType): Option[(List[Type], Scope, Symbol)]
}
-
-
-
-
-
abstract class NullaryMethodTypeExtractor {
def apply(resultType: Type): NullaryMethodType
def unapply(tpe: NullaryMethodType): Option[(Type)]
diff --git a/src/library/scala/reflect/api/Universe.scala b/src/library/scala/reflect/api/Universe.scala
index 03acbdda2c..a3cec3271b 100755
--- a/src/library/scala/reflect/api/Universe.scala
+++ b/src/library/scala/reflect/api/Universe.scala
@@ -10,7 +10,8 @@ abstract class Universe extends Symbols
with Positions
with TreePrinters
with AnnotationInfos
- with StandardDefinitions {
+ with StandardDefinitions
+ with StandardNames {
type Position
val NoPosition: Position
diff --git a/src/library/scala/reflect/macro/Context.scala b/src/library/scala/reflect/macro/Context.scala
index d0a2787fdf..ebbd4735e5 100644
--- a/src/library/scala/reflect/macro/Context.scala
+++ b/src/library/scala/reflect/macro/Context.scala
@@ -12,4 +12,25 @@ trait Context extends api.Universe {
*/
def referenceCapturedVariable(id: Ident): Tree
+ /** Given a tree or type, generate a tree that when executed at runtime produces the original tree or type.
+ * For instance, given the abstract syntax tree representation of the `x + 1` expression:
+ *
+ * Apply(Select(Ident("x"), "+"), List(Literal(Constant(1))))
+ *
+ * The reifier transforms it to the following tree:
+ *
+ * $mr.Apply($mr.Select($mr.Ident($mr.newFreeVar("x", <Int>, x), "+"), List($mr.Literal($mr.Constant(1))))))
+ *
+ * The transformation looks mostly straightforward, but it has its tricky parts:
+ * * Reifier retains symbols and types defined outside the reified tree, however
+ * locally defined entities get erased and replaced with their original trees
+ * * Free variables are detected and wrapped in symbols of the type FreeVar
+ * * Mutable variables that are accessed from a local function are wrapped in refs
+ * * Since reified trees can be compiled outside of the scope they've been created in,
+ * special measures are taken to ensure that all freeVars remain visible
+ *
+ * Typical usage of this function is to retain some of the trees received/created by a macro
+ * into the form that can be inspected (via pattern matching) or compiled/run (by a reflective ToolBox) during the runtime.
+ */
+ def reify(tree: Tree): Tree
}
diff --git a/src/partest/scala/tools/partest/PartestTask.scala b/src/partest/scala/tools/partest/PartestTask.scala
index a90a61a9aa..524dc06327 100644
--- a/src/partest/scala/tools/partest/PartestTask.scala
+++ b/src/partest/scala/tools/partest/PartestTask.scala
@@ -15,10 +15,8 @@ import scala.tools.nsc.io.{ Directory, Path => SPath }
import nsc.util.ClassPath
import util.PathResolver
import scala.tools.ant.sabbus.CompilationPathProperty
-
import java.io.File
import java.lang.reflect.Method
-
import org.apache.tools.ant.Task
import org.apache.tools.ant.types.{Path, Reference, FileSet}
import org.apache.tools.ant.types.Commandline.Argument
@@ -309,6 +307,16 @@ class PartestTask extends Task with CompilationPathProperty {
val antRunner = new scala.tools.partest.nest.AntRunner
val antFileManager = antRunner.fileManager
+ // this is a workaround for https://issues.scala-lang.org/browse/SI-5433
+ // when that bug is fixed, this paragraph of code can be safely removed
+ // we hack into the classloader that will become parent classloader for scalac
+ // this way we ensure that reflective macro lookup will pick correct Code.lift
+ val loader = getClass.getClassLoader.asInstanceOf[org.apache.tools.ant.AntClassLoader]
+ val path = new org.apache.tools.ant.types.Path(getProject())
+ val newClassPath = ClassPath.join(nest.PathSettings.srcCodeLib.toString, loader.getClasspath)
+ path.setPath(newClassPath)
+ loader.setClassPath(path)
+
antFileManager.showDiff = showDiff
antFileManager.showLog = showLog
antFileManager.failed = runFailed
diff --git a/src/partest/scala/tools/partest/nest/CompileManager.scala b/src/partest/scala/tools/partest/nest/CompileManager.scala
index 6604bc551d..7aaa7bab00 100644
--- a/src/partest/scala/tools/partest/nest/CompileManager.scala
+++ b/src/partest/scala/tools/partest/nest/CompileManager.scala
@@ -12,6 +12,7 @@ import scala.tools.nsc.{ Global, Settings, CompilerCommand, FatalError, io }
import scala.tools.nsc.interactive.RangePositions
import scala.tools.nsc.reporters.{ Reporter, ConsoleReporter }
import scala.tools.nsc.util.{ ClassPath, FakePos }
+import scala.tools.nsc.Properties.{ setProp, propOrEmpty }
import scala.tools.util.PathResolver
import io.Path
import java.io.{ File, BufferedReader, PrintWriter, FileReader, Writer, FileWriter, StringWriter }
@@ -112,6 +113,7 @@ class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler {
try {
NestUI.verbose("compiling "+toCompile)
NestUI.verbose("with classpath: "+global.classPath.toString)
+ NestUI.verbose("and java classpath: "+ propOrEmpty("java.class.path"))
try new global.Run compile toCompile
catch {
case FatalError(msg) =>
diff --git a/src/partest/scala/tools/partest/nest/PathSettings.scala b/src/partest/scala/tools/partest/nest/PathSettings.scala
index 04f36ffa11..e0a2f65b80 100644
--- a/src/partest/scala/tools/partest/nest/PathSettings.scala
+++ b/src/partest/scala/tools/partest/nest/PathSettings.scala
@@ -40,6 +40,13 @@ object PathSettings {
sys.error("No instrumented.jar found in %s".format(srcSpecLibDir))
}
+ // Directory <root>/test/files/codelib
+ lazy val srcCodeLibDir = Directory(srcDir / "codelib")
+
+ lazy val srcCodeLib: File = findJar(srcCodeLibDir, "code") getOrElse {
+ sys.error("No code.jar found in %s".format(srcCodeLibDir))
+ }
+
// Directory <root>/build
lazy val buildDir: Directory = {
val bases = testRoot :: testRoot.parents
diff --git a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala
index 7c6dd0848f..5cde63dc81 100644
--- a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala
+++ b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala
@@ -53,7 +53,13 @@ class ReflectiveRunner {
Array(latestCompFile, latestLibFile, latestPartestFile, latestFjbgFile, latestScalapFile) map (x => io.File(x))
val sepUrls = files map (_.toURL)
- val sepLoader = new URLClassLoader(sepUrls, null)
+ var sepLoader = new URLClassLoader(sepUrls, null)
+
+ // this is a workaround for https://issues.scala-lang.org/browse/SI-5433
+ // when that bug is fixed, this paragraph of code can be safely removed
+ // we hack into the classloader that will become parent classloader for scalac
+ // this way we ensure that reflective macro lookup will pick correct Code.lift
+ sepLoader = new URLClassLoader((PathSettings.srcCodeLib +: files) map (_.toURL), null)
if (isPartestDebug)
println("Loading classes from:\n" + sepUrls.mkString("\n"))
diff --git a/src/partest/scala/tools/partest/nest/TestFile.scala b/src/partest/scala/tools/partest/nest/TestFile.scala
index 3e5fe35f9e..fc5792e886 100644
--- a/src/partest/scala/tools/partest/nest/TestFile.scala
+++ b/src/partest/scala/tools/partest/nest/TestFile.scala
@@ -35,6 +35,10 @@ abstract class TestFile(val kind: String) extends TestFileCommon {
if (setOutDir)
settings.outputDirs setSingleOutput setOutDirTo.path
+ // adding code.jar to the classpath (to provide Code.lift services for reification tests)
+ settings.classpath prepend PathSettings.srcCodeLib.toString
+ if (propIsSet("java.class.path")) setProp("java.class.path", PathSettings.srcCodeLib.toString + ";" + propOrElse("java.class.path", ""))
+
// have to catch bad flags somewhere
(flags forall (f => settings.processArgumentString(f)._1)) && {
settings.classpath append fileManager.CLASSPATH
diff --git a/src/partest/scala/tools/partest/nest/Worker.scala b/src/partest/scala/tools/partest/nest/Worker.scala
index 952d99c318..3f2cb16082 100644
--- a/src/partest/scala/tools/partest/nest/Worker.scala
+++ b/src/partest/scala/tools/partest/nest/Worker.scala
@@ -520,7 +520,9 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor
runTestCommon(file, expectFailure = false)((logFile, outDir) => {
val dir = file.getParentFile
- execTest(outDir, logFile) && diffCheck(compareOutput(dir, logFile))
+ // adding code.jar to the classpath (to provide Code.lift services for reification tests)
+ execTest(outDir, logFile, PathSettings.srcCodeLib.toString) &&
+ diffCheck(compareOutput(dir, logFile))
})
// Apache Ant 1.6 or newer
diff --git a/src/partest/scala/tools/partest/utils/CodeTest.scala b/src/partest/scala/tools/partest/utils/CodeTest.scala
deleted file mode 100644
index c90168a313..0000000000
--- a/src/partest/scala/tools/partest/utils/CodeTest.scala
+++ /dev/null
@@ -1,35 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala Parallel Testing **
-** / __/ __// _ | / / / _ | (c) 2007-2011, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-
-package scala.tools.partest
-package utils
-
-import scala.reflect.Code
-import reflect.runtime.Mirror.ToolBox
-import scala.tools.nsc.reporters._
-import scala.tools.nsc.Settings
-
-/** Runner for testing code tree liftingg
- */
-object CodeTest {
- def static[T](code: () => T, args: Array[String] = Array()) = {
- println("static: "+code())
- }
-
- def apply[T](code: Code[T], args: Array[String] = Array()) = {
- println("testing: "+code.tree)
- val reporter = new ConsoleReporter(new Settings)
- val toolbox = new ToolBox(reporter, args mkString " ")
- val ttree = toolbox.typeCheck(code.tree, code.manifest.tpe)
- println("result = " + toolbox.showAttributed(ttree))
- val evaluated = toolbox.runExpr(ttree)
- println("evaluated = "+evaluated)
- evaluated
- }
-}
diff --git a/src/scalap/scala/tools/scalap/Classfiles.scala b/src/scalap/scala/tools/scalap/Classfiles.scala
index 72b3824157..2cbeaa945f 100644
--- a/src/scalap/scala/tools/scalap/Classfiles.scala
+++ b/src/scalap/scala/tools/scalap/Classfiles.scala
@@ -41,31 +41,5 @@ object Classfiles {
CONSTANT_INTFMETHODREF -> "InterfaceMethod",
CONSTANT_NAMEANDTYPE -> "NameAndType"
)
-
- final val BAD_ATTR = 0x00000
- final val SOURCEFILE_ATTR = 0x00001
- final val SYNTHETIC_ATTR = 0x00002
- final val DEPRECATED_ATTR = 0x00004
- final val CODE_ATTR = 0x00008
- final val EXCEPTIONS_ATTR = 0x00010
- final val CONSTANT_VALUE_ATTR = 0x00020
- final val LINE_NUM_TABLE_ATTR = 0x00040
- final val LOCAL_VAR_TABLE_ATTR = 0x00080
- final val INNERCLASSES_ATTR = 0x08000
- final val META_ATTR = 0x10000
- final val SCALA_ATTR = 0x20000
-
- final val SOURCEFILE_N = "SourceFile"
- final val SYNTHETIC_N = "Synthetic"
- final val DEPRECATED_N = "Deprecated"
- final val CODE_N = "Code"
- final val EXCEPTIONS_N = "Exceptions"
- final val CONSTANT_VALUE_N = "ConstantValue"
- final val LINE_NUM_TABLE_N = "LineNumberTable"
- final val LOCAL_VAR_TABLE_N = "LocalVariableTable"
- final val INNERCLASSES_N = "InnerClasses"
- final val META_N = "JacoMeta"
- final val SCALA_N = "ScalaSignature"
- final val CONSTR_N = "<init>"
}