diff options
Diffstat (limited to 'src')
24 files changed, 232 insertions, 262 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 8114be20d5..6871822562 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") diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala index b1a24c0be2..045daa7eb1 100644 --- a/src/compiler/scala/reflect/internal/StdNames.scala +++ b/src/compiler/scala/reflect/internal/StdNames.scala @@ -271,8 +271,9 @@ trait StdNames extends NameManglers { self: SymbolTable => // Compiler utilized names // val productElementName: NameType = "productElementName" val Ident: NameType = "Ident" - val This: NameType = "This" val StringContext: NameType = "StringContext" + val This: NameType = "This" + val Tree : NameType = "Tree" val TYPE_ : NameType = "TYPE" val TypeTree: NameType = "TypeTree" val UNIT : NameType = "UNIT" @@ -427,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) @@ -464,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) @@ -711,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 @@ -846,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" @@ -880,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/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala index ca7801ac9d..076a7722ae 100644 --- a/src/compiler/scala/reflect/internal/Trees.scala +++ b/src/compiler/scala/reflect/internal/Trees.scala @@ -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 = 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..d4152dffdc 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", diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/ast/Reifiers.scala index d0ed92f8ba..952110ade2 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,174 +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 reifyTyperDebug = settings.Yreifytyperdebug.value - val debugTrace = util.trace when reifyDebug - - val reifyCopypaste = settings.Yreifycopypaste.value - def printCopypaste(tree: Tree) { - if (reifyDebug) println("=======================") - printCopypaste1(tree) - if (reifyDebug) println("=======================") - } - def printCopypaste1(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) - } - } - - 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 { - debugTrace("transforming = ")(if (settings.Xshowtrees.value) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString) - debugTrace("transformed = ") { - val untyped = codify(super.transform(tree)) - if (reifyCopypaste) printCopypaste(untyped) - - printTypings = reifyTyperDebug - val typed = localTyper.typedPos(tree.pos)(untyped) - typed - } - } catch { - case ex: ReifierError => - unit.error(ex.pos, ex.msg) - tree - } finally { - printTypings = saved +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("=======================") } - case _ => - super.transform(tree) - } - } - 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 = // this really should use packedType(tree.tpe, context.owner) - // where packedType is defined in Typers. But we can do that only if liftCode is moved to Typers. - if (tree.tpe.typeSymbol.isAnonymousClass) tree.tpe.typeSymbol.classBound - else tree.tpe - New(TypeTree(appliedType(definitions.CodeClass.typeConstructor, List(treetpe.widen))), - List(List(arg))) + untyped + } + } finally { + printTypings = saved + } + } 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" @@ -434,7 +304,7 @@ abstract class LiftCode extends Transform with TypingTransformers { } case ta @ TypeApply(hk, ts) => if (ts exists isErased) reifyTree(hk) else reifyProduct(ta) - case global.emptyValDef => + case self.emptyValDef => mirrorSelect(nme.emptyValDef) case Literal(constant @ Constant(tpe: Type)) if boundSyms exists (tpe contains _) => CannotReifyClassOfBoundType(tree, tpe) @@ -534,7 +404,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` @@ -558,6 +428,11 @@ abstract class LiftCode extends Transform with TypingTransformers { 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) 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..aebde18703 --- /dev/null +++ b/src/compiler/scala/tools/nsc/ast/ReifyPrinters.scala @@ -0,0 +1,85 @@ +/* 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 + 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 + } + + // @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 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(", ") + ")))" + }) + + 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/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index d1ce460eb9..485a1f3a5c 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -167,8 +167,6 @@ trait ScalaSettings extends AbsScalaSettings val Yreifycopypaste = BooleanSetting ("-Yreify-copypaste", "Dump the reified trees in copypasteable representation.") val Yreifydebug = BooleanSetting ("-Yreify-debug", "Trace reification.") - val Yreifytyperdebug - = BooleanSetting ("-Yreifytyper-debug", "Trace typings of reified trees.") 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/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 036e7fc750..3d2f86d54d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -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..e8c03aff66 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -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..4c790bfc34 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -108,11 +108,14 @@ trait Macros { self: Analyzer => else { val receiverClass: mirror.Symbol = mirror.classWithName(mmeth.owner.fullName) val receiverObj = receiverClass.companionModule - if (receiverObj == NoSymbol) None + if (receiverObj == mirror.NoSymbol) None else { val receiver = mirror.getCompanionObject(receiverClass) val rmeth = receiverObj.info.member(mirror.newTermName(mmeth.name.toString)) - Some((receiver, rmeth)) + if (rmeth == mirror.NoSymbol) None + else { + Some((receiver, rmeth)) + } } } } catch { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index d039515320..eb0bed035c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -708,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 @@ -1993,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) @@ -2011,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 { @@ -2021,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, @@ -2053,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]) { 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/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/Trees.scala b/src/library/scala/reflect/api/Trees.scala index 0a38fb45bf..b8b32477dd 100644 --- a/src/library/scala/reflect/api/Trees.scala +++ b/src/library/scala/reflect/api/Trees.scala @@ -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), "<init>") + (superRef /: argss) (Apply) + } + /** Type annotation, eliminated by explicit outer */ case class Typed(expr: Tree, tpt: Tree) extends TermTree @@ -632,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 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..3b6f96d7a8 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.freeVar("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 c236d89bbd..0000000000 --- a/src/partest/scala/tools/partest/utils/CodeTest.scala +++ /dev/null @@ -1,41 +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) - println("type is: "+code.manifest.tpe) - val isNullary = code.manifest.tpe.typeSymbol == scala.reflect.mirror.definitions.FunctionClass(0) - 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, printTypes = true, printIds = false)) - var evaluated = toolbox.runExpr(ttree) - if (evaluated != null && isNullary) { - val applyMeth = evaluated.getClass.getMethod("apply") - evaluated = applyMeth.invoke(evaluated) - } - println("evaluated = "+evaluated) - evaluated - } -} |