diff options
author | Adriaan Moors <adriaan.moors@epfl.ch> | 2012-07-20 07:47:59 -0700 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@epfl.ch> | 2012-07-20 07:47:59 -0700 |
commit | aca8c1efdb11ec598aa1b2bd94af33c0bb71c9a9 (patch) | |
tree | a29a931144a1b293ce80d4fe74302dda5820dfa0 /src | |
parent | 952cb61108faf1a68e58ee95460e9b3bcad40ea8 (diff) | |
parent | b5f721fb52767d0b839a0ef4614d1bcb039adba1 (diff) | |
download | scala-aca8c1efdb11ec598aa1b2bd94af33c0bb71c9a9.tar.gz scala-aca8c1efdb11ec598aa1b2bd94af33c0bb71c9a9.tar.bz2 scala-aca8c1efdb11ec598aa1b2bd94af33c0bb71c9a9.zip |
Merge pull request #936 from scalamacros/ticket/5999
SI-5999 consistent behavior for c.reify and c.universe.reify
Diffstat (limited to 'src')
22 files changed, 284 insertions, 195 deletions
diff --git a/src/compiler/scala/reflect/makro/runtime/Context.scala b/src/compiler/scala/reflect/makro/runtime/Context.scala index c7563e7b67..68964b7abb 100644 --- a/src/compiler/scala/reflect/makro/runtime/Context.scala +++ b/src/compiler/scala/reflect/makro/runtime/Context.scala @@ -8,7 +8,6 @@ abstract class Context extends scala.reflect.makro.Context with CapturedVariables with Infrastructure with Enclosures - with Mirrors with Names with Reifiers with FrontEnds @@ -23,7 +22,7 @@ abstract class Context extends scala.reflect.makro.Context val universe: Global - val mirror: MirrorOf[universe.type] = new ContextMirror + val mirror: MirrorOf[universe.type] = universe.rootMirror val callsiteTyper: universe.analyzer.Typer diff --git a/src/compiler/scala/reflect/makro/runtime/ContextReifiers.scala b/src/compiler/scala/reflect/makro/runtime/ContextReifiers.scala deleted file mode 100644 index 564148fe6c..0000000000 --- a/src/compiler/scala/reflect/makro/runtime/ContextReifiers.scala +++ /dev/null @@ -1,26 +0,0 @@ -package scala.reflect.makro -package runtime - -abstract class ContextReifiers { self => - val c: Context - - import c.universe._ - import definitions._ - import treeBuild._ - - import scala.reflect.reify.Taggers - import language.implicitConversions - private implicit def context2taggers(c0: Context) : Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers - - private def forMacroContext[T](prefix: Tree)(op: (Tree, Tree) => T): T = { - val universe = gen.mkAttributedSelect(prefix.duplicate, MacroContextUniverse) setType SingleType(prefix.tpe, MacroContextUniverse) - val mirror = TypeApply(Select(Select(prefix.duplicate, nme.mirror), nme.asInstanceOf_), List(Select(Ident(nme.UNIVERSE_SHORT), tpnme.Mirror))) - op(universe, mirror) - } - - def materializeExprForMacroContext(prefix: Tree, expr: Tree): Tree = - forMacroContext(prefix)((universe, mirror) => c.materializeExpr(universe, mirror, expr)) - - def materializeTypeTagForMacroContext(prefix: Tree, tpe: Type, concrete: Boolean): Tree = - forMacroContext(prefix)((universe, mirror) => c.materializeTypeTag(universe, mirror, tpe, concrete)) -}
\ No newline at end of file diff --git a/src/compiler/scala/reflect/makro/runtime/Mirrors.scala b/src/compiler/scala/reflect/makro/runtime/Mirrors.scala deleted file mode 100644 index ec970ee696..0000000000 --- a/src/compiler/scala/reflect/makro/runtime/Mirrors.scala +++ /dev/null @@ -1,43 +0,0 @@ -package scala.reflect.makro -package runtime - -import scala.tools.nsc.util.ScalaClassLoader - -trait Mirrors { - self: Context => - - import universe._ - import definitions._ - - class ContextMirror extends RootsBase(NoSymbol) { - val universe: self.universe.type = self.universe - def rootLoader: LazyType = rootMirror.rootLoader - - val RootPackage = rootMirror.RootPackage - val RootClass = rootMirror.RootClass - val EmptyPackage = rootMirror.EmptyPackage - val EmptyPackageClass = rootMirror.EmptyPackageClass - - // [Eugene++] this still doesn't solve the problem of invoking `c.typeCheck` on the code that refers to packageless symbols - override protected def mirrorMissingHook(owner: Symbol, name: Name): Symbol = { - if (owner.isRoot && isJavaClass(name.toString)) EmptyPackageClass.info decl name - else NoSymbol - } - - private lazy val libraryClasspathLoader: ClassLoader = { - val classpath = platform.classPath.asURLs - ScalaClassLoader.fromURLs(classpath) - } - - private def isJavaClass(path: String): Boolean = - try { - Class.forName(path, true, libraryClasspathLoader) - true - } catch { - case (_: ClassNotFoundException) | (_: NoClassDefFoundError) | (_: IncompatibleClassChangeError) => - false - } - - override def toString = "macro context mirror" - } -}
\ No newline at end of file diff --git a/src/compiler/scala/reflect/reify/Taggers.scala b/src/compiler/scala/reflect/reify/Taggers.scala index e09f13a052..4e30d0acf8 100644 --- a/src/compiler/scala/reflect/reify/Taggers.scala +++ b/src/compiler/scala/reflect/reify/Taggers.scala @@ -37,23 +37,21 @@ abstract class Taggers { } def materializeTypeTag(universe: Tree, mirror: Tree, tpe: Type, concrete: Boolean): Tree = { - if (universe.symbol == MacroContextUniverse && mirror == EmptyTree) { - import scala.reflect.makro.runtime.ContextReifiers - import language.implicitConversions - implicit def context2contextreifiers(c0: Context) : ContextReifiers { val c: c0.type } = new { val c: c0.type = c0 } with ContextReifiers - val Select(prefix, _) = universe - c.materializeTypeTagForMacroContext(prefix, tpe, concrete) - } else { - val tagType = if (concrete) TypeTagClass else AbsTypeTagClass - val unaffiliatedTagTpe = TypeRef(BaseUniverseClass.asTypeConstructor, tagType, List(tpe)) - val unaffiliatedTag = c.inferImplicitValue(unaffiliatedTagTpe, silent = true, withMacrosDisabled = true) - unaffiliatedTag match { - case success if !success.isEmpty => - Apply(Select(success, nme.in), List(mirror orElse mkDefaultMirrorRef(c.universe)(universe, c.callsiteTyper))) - case _ => - val tagModule = if (concrete) TypeTagModule else AbsTypeTagModule - materializeTag(universe, tpe, tagModule, c.reifyType(universe, mirror, tpe, concrete = concrete)) - } + val tagType = if (concrete) TypeTagClass else AbsTypeTagClass + // what we need here is to compose a type BaseUniverse # TypeTag[$tpe] + // to look for an implicit that conforms to this type + // that's why neither appliedType(tagType, List(tpe)) aka TypeRef(TypeTagsClass.thisType, tagType, List(tpe)) + // nor TypeRef(BaseUniverseClass.thisType, tagType, List(tpe)) won't fit here + // scala> :type -v def foo: scala.reflect.base.Universe#TypeTag[Int] = ??? + // NullaryMethodType(TypeRef(pre = TypeRef(TypeSymbol(Universe)), TypeSymbol(TypeTag), args = List($tpe)))) + val unaffiliatedTagTpe = TypeRef(BaseUniverseClass.typeConstructor, tagType, List(tpe)) + val unaffiliatedTag = c.inferImplicitValue(unaffiliatedTagTpe, silent = true, withMacrosDisabled = true) + unaffiliatedTag match { + case success if !success.isEmpty => + Apply(Select(success, nme.in), List(mirror orElse mkDefaultMirrorRef(c.universe)(universe, c.callsiteTyper))) + case _ => + val tagModule = if (concrete) TypeTagModule else AbsTypeTagModule + materializeTag(universe, tpe, tagModule, c.reifyType(universe, mirror, tpe, concrete = concrete)) } } diff --git a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala index 9b0777580b..38c8fedac5 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala @@ -37,10 +37,40 @@ trait GenSymbols { mirrorMirrorSelect(nme.EmptyPackageClass) else if (sym.isModuleClass) Select(Select(reify(sym.sourceModule), nme.asModuleSymbol), nme.moduleClass) + else if (sym.isPackage) + mirrorMirrorCall(nme.staticPackage, reify(sym.fullName)) else if (sym.isLocatable) { - // [Eugene] am I doing this right? -// if (sym.isStaticOwner) { // no good for us, because it returns false for packages - if (sym.isStatic && (sym.isClass || sym.isModule)) { + /** This is a fancy conundrum that stems from the fact that Scala allows + * packageless packages and packageless objects with the same names in the same program. + * + * For more details read the docs to staticModule and staticPackage. + * Here I'll just provide the examples of how reify works for different kinds of symbols. + * + * // 1) packageless + * // packageless classes are non-ambiguous, but modules vs packages might be + * // that's why we have separate methods to reify those + * // note that staticModule will never resolve to a package if an object is missing and an homonymous package is present and vice versa + * // otherwise reification would be unsound + * class C => staticClass("C") + * object B => staticModule("B") + * package B => staticPackage("B") + * + * // 2) classes and modules enclosed in a package + * // staticXXX methods always look into parent packages and ignores parent modules, so for fully qualified names they are non-ambiguous + * // namely even if there's an object B { class C } next to package B { class C }, then staticClass("B.C") will resolve to a packageful class + * // this closely mirrors Scala's behavior, read up the docs to staticModule/staticPackage for more information + * package B { class C } => staticClass("B.C") + * package B { object B } => staticModule("B.B") + * package B { package B } => staticPackage("B.B") + * + * // 3) classes and modules enclosed in a packageless module + * // staticClass/staticModule won't look into EmptyPackageClass, so we reify such symbols in a roundabout way + * object B { class C } => selectType(staticModule("B"), "C") + * object B { object B } => selectType(staticModule("B"), "B") + * object B { package B } => impossible + */ + val hasPackagelessParent = sym.ownerChain.tail.tail exists (_.isEmptyPackageClass) + if (sym.isStatic && (sym.isClass || sym.isModule) && !hasPackagelessParent) { val resolver = if (sym.isType) nme.staticClass else nme.staticModule mirrorMirrorCall(resolver, reify(sym.fullName)) } else { diff --git a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala index 82951a2434..c49e5b3342 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala @@ -41,8 +41,7 @@ trait GenTypes { case tpe @ ThisType(empty) if empty.isEmptyPackageClass => mirrorBuildCall(nme.thisPrefix, mirrorMirrorSelect(nme.EmptyPackageClass)) case tpe @ ThisType(clazz) if clazz.isModuleClass && clazz.isStatic => - // [Eugene++ to Martin] makes sense? - val module = mirrorMirrorCall(nme.staticModule, reify(clazz.fullName)) + val module = reify(clazz.sourceModule) val moduleClass = Select(Select(module, nme.asModuleSymbol), nme.moduleClass) mirrorFactoryCall(nme.ThisType, moduleClass) case tpe @ ThisType(_) => diff --git a/src/compiler/scala/reflect/reify/utils/Extractors.scala b/src/compiler/scala/reflect/reify/utils/Extractors.scala index 52e4ff08c1..86265ec77a 100644 --- a/src/compiler/scala/reflect/reify/utils/Extractors.scala +++ b/src/compiler/scala/reflect/reify/utils/Extractors.scala @@ -27,7 +27,7 @@ trait Extractors { // def applyImpl[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.base.MirrorOf[U]): U#Tree = { // val $u: U = $m$untyped.universe; // val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror]; - // $u.Apply($u.Select($u.Select($u.build.This($m.staticModule("scala.collection.immutable").moduleClass), $u.newTermName("List")), $u.newTermName("apply")), List($u.Literal($u.Constant(1)), $u.Literal($u.Constant(2)))) + // $u.Apply($u.Select($u.Select($u.build.This($m.staticPackage("scala.collection.immutable").moduleClass), $u.newTermName("List")), $u.newTermName("apply")), List($u.Literal($u.Constant(1)), $u.Literal($u.Constant(2)))) // } // }; // new $treecreator1() @@ -40,7 +40,7 @@ trait Extractors { // def apply[U >: Nothing <: scala.reflect.base.Universe with Singleton]($m$untyped: scala.reflect.base.MirrorOf[U]): U#Type = { // val $u: U = $m$untyped.universe; // val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror]; - // $u.TypeRef($u.ThisType($m.staticModule("scala.collection.immutable").moduleClass), $m.staticClass("scala.collection.immutable.List"), List($m.staticClass("scala.Int").asTypeConstructor)) + // $u.TypeRef($u.ThisType($m.staticPackage("scala.collection.immutable").moduleClass), $m.staticClass("scala.collection.immutable.List"), List($m.staticClass("scala.Int").asTypeConstructor)) // } // }; // new $typecreator1() diff --git a/src/compiler/scala/tools/cmd/FromString.scala b/src/compiler/scala/tools/cmd/FromString.scala index 29f1baaa0c..415940b3fd 100644 --- a/src/compiler/scala/tools/cmd/FromString.scala +++ b/src/compiler/scala/tools/cmd/FromString.scala @@ -8,7 +8,7 @@ package cmd import nsc.io.{ Path, File, Directory } import scala.reflect.runtime.{universe => ru} -import scala.tools.reflect.StdTags._ +import scala.tools.reflect.StdRuntimeTags._ /** A general mechanism for defining how a command line argument * (always a String) is transformed into an arbitrary type. A few diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala index e5e7d7081d..b567293a3f 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala @@ -25,7 +25,7 @@ import ScalaClassLoader._ import scala.tools.util._ import language.{implicitConversions, existentials} import scala.reflect.{ClassTag, classTag} -import scala.tools.reflect.StdTags._ +import scala.tools.reflect.StdRuntimeTags._ /** The Scala interactive shell. It provides a read-eval-print loop * around the Interpreter class. diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index b385787cce..7bdbff8627 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -28,7 +28,7 @@ import typechecker.Analyzer import language.implicitConversions import scala.reflect.runtime.{ universe => ru } import scala.reflect.{ ClassTag, classTag } -import scala.tools.reflect.StdTags._ +import scala.tools.reflect.StdRuntimeTags._ /** directory to save .class files to */ private class ReplVirtualDirectory(out: JPrintWriter) extends VirtualDirectory("(memory)", None) { diff --git a/src/compiler/scala/tools/reflect/FastTrack.scala b/src/compiler/scala/tools/reflect/FastTrack.scala index 63ecfa32b2..237ef813c7 100644 --- a/src/compiler/scala/tools/reflect/FastTrack.scala +++ b/src/compiler/scala/tools/reflect/FastTrack.scala @@ -1,7 +1,6 @@ package scala.tools package reflect -import scala.reflect.makro.runtime.ContextReifiers import scala.reflect.reify.Taggers import scala.tools.nsc.typechecker.{Analyzer, Macros} @@ -16,7 +15,6 @@ trait FastTrack { import language.implicitConversions private implicit def context2taggers(c0: MacroContext): Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers - private implicit def context2contextreifiers(c0: MacroContext): ContextReifiers { val c: c0.type } = new { val c: c0.type = c0 } with ContextReifiers private implicit def context2macroimplementations(c0: MacroContext): MacroImplementations { val c: c0.type } = new { val c: c0.type = c0 } with MacroImplementations implicit def fastTrackEntry2MacroRuntime(entry: FastTrackEntry): MacroRuntime = args => entry.run(args) @@ -41,7 +39,6 @@ trait FastTrack { MacroInternal_materializeAbsTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, EmptyTree, tt.tpe, concrete = false) } MacroInternal_materializeTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, EmptyTree, tt.tpe, concrete = true) } ApiUniverseReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExpr(c.prefix.tree, EmptyTree, expr) } - MacroContextReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExprForMacroContext(c.prefix.tree, expr) } ReflectRuntimeCurrentMirror bindTo { case (c, _) => scala.reflect.runtime.Macros.currentMirror(c).tree } StringContext_f bindTo { case (c, app@Apply(Select(Apply(_, parts), _), args)) => c.macro_StringInterpolation_f(parts, args, app.pos) } registry diff --git a/src/compiler/scala/tools/reflect/MacroImplementations.scala b/src/compiler/scala/tools/reflect/MacroImplementations.scala index 604bd7cd1a..e1b959cefa 100644 --- a/src/compiler/scala/tools/reflect/MacroImplementations.scala +++ b/src/compiler/scala/tools/reflect/MacroImplementations.scala @@ -57,6 +57,9 @@ abstract class MacroImplementations { ) } + val stdContextTags = new { val tc: c.type = c } with StdContextTags + import stdContextTags._ + def conversionType(ch: Char, arg: Tree): Option[Type] = { ch match { case 'b' | 'B' => @@ -68,11 +71,11 @@ abstract class MacroImplementations { case 'c' | 'C' => checkType(arg, CharTpe, ByteTpe, ShortTpe, IntTpe) case 'd' | 'o' | 'x' | 'X' => - checkType(arg, IntTpe, LongTpe, ByteTpe, ShortTpe, typeOf[BigInt]) + checkType(arg, IntTpe, LongTpe, ByteTpe, ShortTpe, tagOfBigInt.tpe) case 'e' | 'E' | 'g' | 'G' | 'f' | 'a' | 'A' => - checkType(arg, DoubleTpe, FloatTpe, typeOf[BigDecimal]) + checkType(arg, DoubleTpe, FloatTpe, tagOfBigDecimal.tpe) case 't' | 'T' => - checkType(arg, LongTpe, typeOf[java.util.Calendar], typeOf[java.util.Date]) + checkType(arg, LongTpe, tagOfCalendar.tpe, tagOfDate.tpe) case _ => None } } diff --git a/src/compiler/scala/tools/reflect/StdTags.scala b/src/compiler/scala/tools/reflect/StdTags.scala index 18cbf9c4b7..25a42a82cd 100644 --- a/src/compiler/scala/tools/reflect/StdTags.scala +++ b/src/compiler/scala/tools/reflect/StdTags.scala @@ -4,46 +4,55 @@ package reflect import java.lang.{Class => jClass} import scala.reflect.{ClassTag, classTag} import scala.reflect.base.{MirrorOf, TypeCreator, Universe => BaseUniverse} -import scala.reflect.runtime.{universe => ru} // [Eugene++] Before 2.10 is released, I suggest we don't rely on automated type tag generation // sure, it's convenient, but then refactoring reflection / reification becomes a pain // `ClassTag` tags are fine, because they don't need a reifier to be generated -object StdTags { - // root mirror is fine for these guys, since scala-library.jar is guaranteed to be reachable from the root mirror - lazy val tagOfString = ru.TypeTag[String]( - ru.rootMirror, - new TypeCreator { - def apply[U <: BaseUniverse with Singleton](m: MirrorOf[U]): U # Type = { - val u = m.universe - u.definitions.StringClass.asTypeConstructor - } - }) - lazy val tagOfListOfString = ru.TypeTag[List[String]]( - ru.rootMirror, - new TypeCreator { - def apply[U <: BaseUniverse with Singleton](m: MirrorOf[U]): U # Type = { - val u = m.universe - val pre = u.ThisType(m.staticModule("scala.collection.immutable").moduleClass.asInstanceOf[u.Symbol]) - u.TypeRef(pre, u.definitions.ListClass, List(u.definitions.StringClass.asTypeConstructor)) - } - }) +trait StdTags { + val u: BaseUniverse with Singleton + val m: MirrorOf[u.type] - // root mirror is NOT fine for these guys, hence we use the `currentMirror` trick - private val ourClassloader = getClass.getClassLoader - private def tagOfStaticClass[T: ClassTag] = - ru.TypeTag[T]( - ru.runtimeMirror(ourClassloader), + lazy val tagOfListOfString: u.TypeTag[List[String]] = + u.TypeTag[List[String]]( + m, + new TypeCreator { + def apply[U <: BaseUniverse with Singleton](m: MirrorOf[U]): U # Type = { + val u = m.universe + val pre = u.ThisType(m.staticPackage("scala.collection.immutable").moduleClass.asInstanceOf[u.Symbol]) + u.TypeRef(pre, u.definitions.ListClass, List(u.definitions.StringClass.asTypeConstructor)) + } + }) + + private def tagOfStaticClass[T: ClassTag]: u.TypeTag[T] = + u.TypeTag[T]( + m, new TypeCreator { def apply[U <: BaseUniverse with Singleton](m: MirrorOf[U]): U # Type = m.staticClass(classTag[T].runtimeClass.getName).asTypeConstructor.asInstanceOf[U # Type] }) - lazy val tagOfInt = ru.TypeTag.Int + lazy val tagOfInt = u.TypeTag.Int + lazy val tagOfString = tagOfStaticClass[String] lazy val tagOfFile = tagOfStaticClass[scala.tools.nsc.io.File] lazy val tagOfDirectory = tagOfStaticClass[scala.tools.nsc.io.Directory] lazy val tagOfStdReplVals = tagOfStaticClass[scala.tools.nsc.interpreter.StdReplVals] lazy val tagOfIMain = tagOfStaticClass[scala.tools.nsc.interpreter.IMain] lazy val tagOfThrowable = tagOfStaticClass[java.lang.Throwable] lazy val tagOfClassLoader = tagOfStaticClass[java.lang.ClassLoader] + lazy val tagOfBigInt = tagOfStaticClass[BigInt] + lazy val tagOfBigDecimal = tagOfStaticClass[BigDecimal] + lazy val tagOfCalendar = tagOfStaticClass[java.util.Calendar] + lazy val tagOfDate = tagOfStaticClass[java.util.Date] +} + +object StdRuntimeTags extends StdTags { + val u: scala.reflect.runtime.universe.type = scala.reflect.runtime.universe + val m = u.runtimeMirror(getClass.getClassLoader) + // we need getClass.getClassLoader to support the stuff from scala-compiler.jar +} + +abstract class StdContextTags extends StdTags { + val tc: scala.reflect.makro.Context + val u: tc.universe.type = tc.universe + val m = tc.mirror } diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala index 3a1dc87a6a..46c644bcd6 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala @@ -36,7 +36,7 @@ trait CPSUtils { lazy val MarkerCPSAdaptMinus = rootMirror.getRequiredClass("scala.util.continuations.cpsMinus") lazy val Context = rootMirror.getRequiredClass("scala.util.continuations.ControlContext") - lazy val ModCPS = rootMirror.getRequiredModule("scala.util.continuations") + lazy val ModCPS = rootMirror.getRequiredPackage("scala.util.continuations") lazy val MethShiftUnit = definitions.getMember(ModCPS, cpsNames.shiftUnit) lazy val MethShiftUnit0 = definitions.getMember(ModCPS, cpsNames.shiftUnit0) diff --git a/src/library/scala/reflect/base/Base.scala b/src/library/scala/reflect/base/Base.scala index a4e6256f4d..4457a6cf14 100644 --- a/src/library/scala/reflect/base/Base.scala +++ b/src/library/scala/reflect/base/Base.scala @@ -357,6 +357,9 @@ class Base extends Universe { self => def staticModule(fullName: String): ModuleSymbol = mkStatic[ModuleSymbol](fullName) + def staticPackage(fullName: String): ModuleSymbol = + staticModule(fullName) // this toy universe doesn't care about the distinction between packages and modules + private def mkStatic[S <: Symbol : ClassTag](fullName: String): S = cached(fullName) { val point = fullName lastIndexOf '.' diff --git a/src/library/scala/reflect/base/MirrorOf.scala b/src/library/scala/reflect/base/MirrorOf.scala index 03e035cd81..6dc8090eee 100644 --- a/src/library/scala/reflect/base/MirrorOf.scala +++ b/src/library/scala/reflect/base/MirrorOf.scala @@ -15,11 +15,76 @@ abstract class MirrorOf[U <: base.Universe with Singleton] { /** The symbol corresponding to the globally accessible class with the * given fully qualified name `fullName`. + * + * If the name points to a type alias, it's recursively dealiased and its target is returned. + * If you need a symbol that corresponds to the type alias itself, load it directly from the package class: + * + * scala> cm.staticClass("scala.List") + * res0: reflect.runtime.universe.ClassSymbol = class List + * + * scala> res0.fullName + * res1: String = scala.collection.immutable.List + * + * scala> cm.staticPackage("scala") + * res2: reflect.runtime.universe.ModuleSymbol = package scala + * + * scala> res2.moduleClass.typeSignature member newTypeName("List") + * res3: reflect.runtime.universe.Symbol = type List + * + * scala> res3.fullName + * res4: String = scala.List + * + * To be consistent with Scala name resolution rules, in case of ambiguity between + * a package and an object, the object is never been considered. + * + * For example for the following code: + * + * package foo { + * class B + * } + * + * object foo { + * class A + * class B + * } + * + * staticClass("foo.B") will resolve to the symbol corresponding to the class B declared in the package foo, and + * staticClass("foo.A") will throw a MissingRequirementException (which is exactly what scalac would do if this + * fully qualified class name is written inside any package in a Scala program). + * + * In the example above, to load a symbol that corresponds to the class B declared in the object foo, + * use staticModule("foo") to load the module symbol and then navigate typeSignature.members of its moduleClass. */ def staticClass(fullName: String): U#ClassSymbol /** The symbol corresponding to the globally accessible object with the * given fully qualified name `fullName`. + * + * To be consistent with Scala name resolution rules, in case of ambiguity between + * a package and an object, the object is never been considered. + * + * For example for the following code: + * + * package foo { + * object B + * } + * + * object foo { + * object A + * object B + * } + * + * staticModule("foo.B") will resolve to the symbol corresponding to the object B declared in the package foo, and + * staticModule("foo.A") will throw a MissingRequirementException (which is exactly what scalac would do if this + * fully qualified class name is written inside any package in a Scala program). + * + * In the example above, to load a symbol that corresponds to the object B declared in the object foo, + * use staticModule("foo") to load the module symbol and then navigate typeSignature.members of its moduleClass. */ def staticModule(fullName: String): U#ModuleSymbol + + /** The symbol corresponding to a package with the + * given fully qualified name `fullName`. + */ + def staticPackage(fullName: String): U#ModuleSymbol } diff --git a/src/partest/scala/tools/partest/CompilerTest.scala b/src/partest/scala/tools/partest/CompilerTest.scala index 89c1a9c2ca..fec9893099 100644 --- a/src/partest/scala/tools/partest/CompilerTest.scala +++ b/src/partest/scala/tools/partest/CompilerTest.scala @@ -50,7 +50,7 @@ abstract class CompilerTest extends DirectTest { } class SymsInPackage(pkgName: String) { - def pkg = rootMirror.getRequiredModule(pkgName) + def pkg = rootMirror.getRequiredPackage(pkgName) def classes = allMembers(pkg) filter (_.isClass) def modules = allMembers(pkg) filter (_.isModule) def symbols = classes ++ terms filterNot (_ eq NoSymbol) diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index cd243b9df0..7284a199b7 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -490,7 +490,6 @@ trait Definitions extends api.StandardDefinitions { def MacroContextPrefixType = if (MacroContextClass != NoSymbol) getMemberType(MacroContextClass, tpnme.PrefixType) else NoSymbol def MacroContextUniverse = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.universe) else NoSymbol def MacroContextMirror = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.mirror) else NoSymbol - def MacroContextReify = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.reify) else NoSymbol lazy val MacroImplAnnotation = requiredClass[scala.reflect.makro.internal.macroImpl] lazy val MacroInternalPackage = getPackageObject("scala.reflect.makro.internal") def MacroInternal_materializeClassTag = getMemberMethod(MacroInternalPackage, nme.materializeClassTag) diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala index 761b993539..f7561ae274 100644 --- a/src/reflect/scala/reflect/internal/Mirrors.scala +++ b/src/reflect/scala/reflect/internal/Mirrors.scala @@ -36,7 +36,7 @@ trait Mirrors extends api.Mirrors { if (point > 0) getModuleOrClass(path.toTermName, point) else RootClass val name = path subName (point + 1, len) - val sym = owner.info member name + var sym = owner.info member name val result = if (path.isTermName) sym.suchThat(_ hasFlag MODULE) else sym if (result != NoSymbol) result else { @@ -47,23 +47,39 @@ trait Mirrors extends api.Mirrors { } } - protected def mirrorMissingHook(owner: Symbol, name: Name): Symbol = NoSymbol - - protected def symbolTableMissingHook(owner: Symbol, name: Name): Symbol = self.missingHook(owner, name) - - private[scala] def missingHook(owner: Symbol, name: Name): Symbol = mirrorMissingHook(owner, name) orElse symbolTableMissingHook(owner, name) + /** If you're looking for a class, pass a type name. + * If a module, a term name. + * + * Unlike `getModuleOrClass`, this function + * loads unqualified names from the root package. + */ + private def getModuleOrClass(path: Name): Symbol = + getModuleOrClass(path, path.length) /** If you're looking for a class, pass a type name. * If a module, a term name. + * + * Unlike `getModuleOrClass`, this function + * loads unqualified names from the empty package. */ - private def getModuleOrClass(path: Name): Symbol = getModuleOrClass(path, path.length) + private def staticModuleOrClass(path: Name): Symbol = { + val isPackageless = path.pos('.') == path.length + if (isPackageless) EmptyPackageClass.info decl path + else getModuleOrClass(path) + } + + protected def mirrorMissingHook(owner: Symbol, name: Name): Symbol = NoSymbol + + protected def universeMissingHook(owner: Symbol, name: Name): Symbol = self.missingHook(owner, name) - override def staticClass(fullName: String): ClassSymbol = getRequiredClass(fullName) + private[scala] def missingHook(owner: Symbol, name: Name): Symbol = mirrorMissingHook(owner, name) orElse universeMissingHook(owner, name) - // todo: get rid of most creation methods and keep just staticClass/Module/Package + // todo: get rid of most the methods here and keep just staticClass/Module/Package - def getClassByName(fullname: Name): ClassSymbol = { - var result = getModuleOrClass(fullname.toTypeName) + /************************ loaders of class symbols ************************/ + + private def ensureClassSymbol(fullname: String, sym: Symbol): ClassSymbol = { + var result = sym while (result.isAliasType) result = result.info.typeSymbol result match { case x: ClassSymbol => x @@ -71,45 +87,50 @@ trait Mirrors extends api.Mirrors { } } - override def staticModule(fullName: String): ModuleSymbol = getRequiredModule(fullName) + @deprecated("Use getClassByName", "2.10.0") + def getClass(fullname: Name): ClassSymbol = + getClassByName(fullname) - def getModule(fullname: Name): ModuleSymbol = - // [Eugene++] should be a ClassCastException instead? - getModuleOrClass(fullname.toTermName) match { - case x: ModuleSymbol => x - case _ => MissingRequirementError.notFound("object " + fullname) - } + def getClassByName(fullname: Name): ClassSymbol = + ensureClassSymbol(fullname.toString, getModuleOrClass(fullname.toTypeName)) - def getPackage(fullname: Name): ModuleSymbol = getModule(fullname) + def getRequiredClass(fullname: String): ClassSymbol = + getClassByName(newTypeNameCached(fullname)) - def getRequiredPackage(fullname: String): ModuleSymbol = - getPackage(newTermNameCached(fullname)) + def requiredClass[T: ClassTag] : ClassSymbol = + getRequiredClass(erasureName[T]) - @deprecated("Use getClassByName", "2.10.0") - def getClass(fullname: Name): ClassSymbol = getClassByName(fullname) + def getClassIfDefined(fullname: String): Symbol = + getClassIfDefined(newTypeNameCached(fullname)) - def getRequiredClass(fullname: String): ClassSymbol = - getClassByName(newTypeNameCached(fullname)) match { - case x: ClassSymbol => x - case _ => MissingRequirementError.notFound("class " + fullname) - } + def getClassIfDefined(fullname: Name): Symbol = + wrapMissing(getClassByName(fullname.toTypeName)) - def getRequiredModule(fullname: String): ModuleSymbol = - getModule(newTermNameCached(fullname)) + /** @inheritdoc + * + * Unlike getClassByName/getRequiredClass this function can also load packageless symbols. + * Compiler might ignore them, but they should be loadable with macros. + */ + override def staticClass(fullname: String): ClassSymbol = + ensureClassSymbol(fullname, staticModuleOrClass(newTypeNameCached(fullname))) - def erasureName[T: ClassTag] : String = { - /** We'd like the String representation to be a valid - * scala type, so we have to decode the jvm's secret language. - */ - def erasureString(clazz: Class[_]): String = { - if (clazz.isArray) "Array[" + erasureString(clazz.getComponentType) + "]" - else clazz.getName + /************************ loaders of module symbols ************************/ + + private def ensureModuleSymbol(fullname: String, sym: Symbol, allowPackages: Boolean): ModuleSymbol = + sym match { + case x: ModuleSymbol if allowPackages || !x.isPackage => x + case _ => MissingRequirementError.notFound("object " + fullname) } - erasureString(classTag[T].runtimeClass) - } - def requiredClass[T: ClassTag] : ClassSymbol = - getRequiredClass(erasureName[T]) + @deprecated("Use getModuleByName", "2.10.0") + def getModule(fullname: Name): ModuleSymbol = + getModuleByName(fullname) + + def getModuleByName(fullname: Name): ModuleSymbol = + ensureModuleSymbol(fullname.toString, getModuleOrClass(fullname.toTermName), allowPackages = true) + + def getRequiredModule(fullname: String): ModuleSymbol = + getModule(newTermNameCached(fullname)) // TODO: What syntax do we think should work here? Say you have an object // like scala.Predef. You can't say requiredModule[scala.Predef] since there's @@ -121,34 +142,60 @@ trait Mirrors extends api.Mirrors { def requiredModule[T: ClassTag] : ModuleSymbol = getRequiredModule(erasureName[T] stripSuffix "$") - def getClassIfDefined(fullname: String): Symbol = - getClassIfDefined(newTypeName(fullname)) - - def getClassIfDefined(fullname: Name): Symbol = - wrapMissing(getClassByName(fullname.toTypeName)) - def getModuleIfDefined(fullname: String): Symbol = - getModuleIfDefined(newTermName(fullname)) + getModuleIfDefined(newTermNameCached(fullname)) def getModuleIfDefined(fullname: Name): Symbol = wrapMissing(getModule(fullname.toTermName)) + /** @inheritdoc + * + * Unlike getModule/getRequiredModule this function can also load packageless symbols. + * Compiler might ignore them, but they should be loadable with macros. + */ + override def staticModule(fullname: String): ModuleSymbol = + ensureModuleSymbol(fullname, staticModuleOrClass(newTermNameCached(fullname)), allowPackages = false) + + /************************ loaders of package symbols ************************/ + + private def ensurePackageSymbol(fullname: String, sym: Symbol, allowModules: Boolean): ModuleSymbol = + sym match { + case x: ModuleSymbol if allowModules || x.isPackage => x + case _ => MissingRequirementError.notFound("package " + fullname) + } + + def getPackage(fullname: Name): ModuleSymbol = + ensurePackageSymbol(fullname.toString, getModuleOrClass(fullname), allowModules = true) + + def getRequiredPackage(fullname: String): ModuleSymbol = + getPackage(newTermNameCached(fullname)) + def getPackageObject(fullname: String): ModuleSymbol = - (getModule(newTermName(fullname)).info member nme.PACKAGE) match { + (getPackage(newTermName(fullname)).info member nme.PACKAGE) match { case x: ModuleSymbol => x case _ => MissingRequirementError.notFound("package object " + fullname) } - def getPackageObjectIfDefined(fullname: String): Symbol = { - val module = getModuleIfDefined(newTermName(fullname)) - if (module == NoSymbol) NoSymbol - else { - val packageObject = module.info member nme.PACKAGE - packageObject match { - case x: ModuleSymbol => x - case _ => NoSymbol - } + def getPackageObjectIfDefined(fullname: String): Symbol = + getPackageObjectIfDefined(newTermNameCached(fullname)) + + def getPackageObjectIfDefined(fullname: Name): Symbol = + wrapMissing(getPackageObject(fullname.toTermName)) + + override def staticPackage(fullname: String): ModuleSymbol = + ensurePackageSymbol(fullname.toString, getModuleOrClass(newTermNameCached(fullname)), allowModules = false) + + /************************ helpers ************************/ + + def erasureName[T: ClassTag] : String = { + /** We'd like the String representation to be a valid + * scala type, so we have to decode the jvm's secret language. + */ + def erasureString(clazz: Class[_]): String = { + if (clazz.isArray) "Array[" + erasureString(clazz.getComponentType) + "]" + else clazz.getName } + erasureString(classTag[T].runtimeClass) } @inline private def wrapMissing(body: => Symbol): Symbol = diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index c8a2424118..e5d0e96d9c 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -754,6 +754,7 @@ trait StdNames { val splice: NameType = "splice" val staticClass : NameType = "staticClass" val staticModule : NameType = "staticModule" + val staticPackage : NameType = "staticPackage" val synchronized_ : NameType = "synchronized" val tail: NameType = "tail" val `then` : NameType = "then" diff --git a/src/reflect/scala/reflect/makro/Context.scala b/src/reflect/scala/reflect/makro/Context.scala index f9858a063c..f093016a38 100644 --- a/src/reflect/scala/reflect/makro/Context.scala +++ b/src/reflect/scala/reflect/makro/Context.scala @@ -33,8 +33,4 @@ trait Context extends Aliases /** The prefix tree from which the macro is selected */ val prefix: Expr[PrefixType] - - /** Alias to the underlying mirror's reify */ - // implementation is magically hardwired to `scala.reflect.makro.runtime.ContextReifiers` - def reify[T](expr: T): Expr[T] = macro ??? } diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 9f9f79058d..0878801715 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -72,6 +72,18 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym override def complete(sym: Symbol) = sym setInfo new LazyPackageType } + // reflective mirrors can't know the exhaustive list of available packages + // (that's because compiler mirrors are based on directories and reflective mirrors are based on classloaders, + // and unlike directories classloaders might make up stuff on the fly) + // hence we need to be optimistic and create packages out of thin air + // the same thing is done by the `missingHook` below + override def staticPackage(fullname: String): ModuleSymbol = + try super.staticPackage(fullname) + catch { + case _: MissingRequirementError => + makeScalaPackage(fullname) + } + // ----------- Caching ------------------------------------------------------------------ // [Eugene++ to Martin] not weak? why? |