summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-07-20 12:46:05 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-07-20 14:39:38 +0200
commitb5f721fb52767d0b839a0ef4614d1bcb039adba1 (patch)
tree61e650f7dfb8921f08cc4aa647de28a15dcfa368 /src/reflect
parente5161f01111c88de4f890c7541a6ff5e7be58916 (diff)
downloadscala-b5f721fb52767d0b839a0ef4614d1bcb039adba1.tar.gz
scala-b5f721fb52767d0b839a0ef4614d1bcb039adba1.tar.bz2
scala-b5f721fb52767d0b839a0ef4614d1bcb039adba1.zip
SI-5999 a real fix to the packageless problem
After a discussion on a reflection meeting on Jul 17 we concluded that we should split staticModule into staticModule and staticPackage to remove the ambiguity between packageless objects and packageless packages (more in the comments in the body of the commit). The motivation is verbosely outlined in the comments, but the bottom line is that Scala allows packages and packageless objects to have the same name within the same program. Therefore at times we need to disambiguate, hence the introduction of the staticPackage method. As of such staticModule no longer works for packages. In the same fashion staticPackage doesn't work for modules. This is done to ensure robustness of reification. I would like to do the same for getModule in Definitions, but we have to maintain backward compatibility. That's why I retained the old behavior, but replaced getModule invocations with getPackage where appropriate to be in line with staticModule and staticPackage. Another important thing that follows from the discussion is that both staticClass and staticModule prefer parent packages over parent objects in cases of ambiguity. Say, if we have the following snippet of code: object B { class C } next to package B { class C } then staticClass("B.C") will never even consider a C inside the object B. This is how scalac operates, so we decided to be consistent here. Finally reification logic got changed to distinguish between staticModule and staticPackage, and to allow for the fact that staticClass and staticModule prefer parent packages to parent objects.
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/scala/reflect/internal/Mirrors.scala99
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala1
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala12
3 files changed, 71 insertions, 41 deletions
diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala
index 100168a69d..f7561ae274 100644
--- a/src/reflect/scala/reflect/internal/Mirrors.scala
+++ b/src/reflect/scala/reflect/internal/Mirrors.scala
@@ -29,24 +29,14 @@ trait Mirrors extends api.Mirrors {
else definitions.findNamedMember(segs.tail, RootClass.info member segs.head)
}
- /** If you're looking for a class, pass a type name.
- * If a module, a term name.
- *
- * `tryPackageless` tells this function to search for requested a requested symbol in EmptyPackageClass as well.
- * Compiler might ignore them, but they should be loadable with macros if the programmer wishes.
- * More info here: http://groups.google.com/group/scala-internals/browse_thread/thread/5146021fd7c0cec
- */
- private def getModuleOrClass(path: Name, tryPackageless: Boolean): Symbol = getModuleOrClass(path, path.length, tryPackageless)
-
/** Todo: organize similar to mkStatic in reflect.Base */
- private def getModuleOrClass(path: Name, len: Int, tryPackageless: Boolean): Symbol = {
+ private def getModuleOrClass(path: Name, len: Int): Symbol = {
val point = path lastPos('.', len - 1)
val owner =
- if (point > 0) getModuleOrClass(path.toTermName, point, tryPackageless)
+ if (point > 0) getModuleOrClass(path.toTermName, point)
else RootClass
val name = path subName (point + 1, len)
var sym = owner.info member name
- if (sym == NoSymbol && owner == RootClass && tryPackageless) sym = EmptyPackageClass.info decl name
val result = if (path.isTermName) sym.suchThat(_ hasFlag MODULE) else sym
if (result != NoSymbol) result
else {
@@ -57,6 +47,27 @@ trait Mirrors extends api.Mirrors {
}
}
+ /** 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 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)
@@ -67,8 +78,8 @@ trait Mirrors extends api.Mirrors {
/************************ loaders of class symbols ************************/
- private def getClassImpl(fullname: TypeName, tryPackageless: Boolean): ClassSymbol = {
- var result = getModuleOrClass(fullname.toTypeName, tryPackageless)
+ private def ensureClassSymbol(fullname: String, sym: Symbol): ClassSymbol = {
+ var result = sym
while (result.isAliasType) result = result.info.typeSymbol
result match {
case x: ClassSymbol => x
@@ -81,7 +92,7 @@ trait Mirrors extends api.Mirrors {
getClassByName(fullname)
def getClassByName(fullname: Name): ClassSymbol =
- getClassImpl(fullname.toTypeName, tryPackageless = false)
+ ensureClassSymbol(fullname.toString, getModuleOrClass(fullname.toTypeName))
def getRequiredClass(fullname: String): ClassSymbol =
getClassByName(newTypeNameCached(fullname))
@@ -90,33 +101,33 @@ trait Mirrors extends api.Mirrors {
getRequiredClass(erasureName[T])
def getClassIfDefined(fullname: String): Symbol =
- getClassIfDefined(newTypeName(fullname))
+ getClassIfDefined(newTypeNameCached(fullname))
def getClassIfDefined(fullname: Name): Symbol =
wrapMissing(getClassByName(fullname.toTypeName))
- /** Unlike getClassByName/getRequiredClass this function can also load packageless symbols.
+ /** @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 =
- getClassImpl(newTypeNameCached(fullname), tryPackageless = true)
+ ensureClassSymbol(fullname, staticModuleOrClass(newTypeNameCached(fullname)))
/************************ loaders of module symbols ************************/
- private def getModuleImpl(fullname: TermName, tryPackageless: Boolean): ModuleSymbol = {
- var result = getModuleOrClass(fullname, tryPackageless)
- result match {
- case x: ModuleSymbol => x
- case _ => MissingRequirementError.notFound("object " + fullname)
+ 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)
}
- }
@deprecated("Use getModuleByName", "2.10.0")
def getModule(fullname: Name): ModuleSymbol =
getModuleByName(fullname)
def getModuleByName(fullname: Name): ModuleSymbol =
- getModuleImpl(fullname.toTermName, tryPackageless = false)
+ ensureModuleSymbol(fullname.toString, getModuleOrClass(fullname.toTermName), allowPackages = true)
def getRequiredModule(fullname: String): ModuleSymbol =
getModule(newTermNameCached(fullname))
@@ -132,41 +143,47 @@ trait Mirrors extends api.Mirrors {
getRequiredModule(erasureName[T] stripSuffix "$")
def getModuleIfDefined(fullname: String): Symbol =
- getModuleIfDefined(newTermName(fullname))
+ getModuleIfDefined(newTermNameCached(fullname))
def getModuleIfDefined(fullname: Name): Symbol =
wrapMissing(getModule(fullname.toTermName))
- /** Unlike getModule/getRequiredModule this function can also load packageless symbols.
+ /** @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 =
- getModuleImpl(newTermNameCached(fullname), tryPackageless = true)
+ ensureModuleSymbol(fullname, staticModuleOrClass(newTermNameCached(fullname)), allowPackages = false)
/************************ loaders of package symbols ************************/
- def getPackage(fullname: Name): ModuleSymbol = getModule(fullname)
+ 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 ************************/
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/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?