From 30f5a36941aa1671849322ba79ebff0881ae7ff0 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 17 Jul 2012 12:36:11 +0200 Subject: SI-5999 removes Context.reify Currently there are discrepancies between the behavior of c.reify and c.universe.reify. First step in fixing these problems is removing the duplication in the API. That's why I'm cutting away the Context.reify shortcut. Context.reify is a magic macro, hardwired in the fast track mechanism, so removing it requires redeploying the starr (because an old starr will crash if launched on sources that don't contain Context.reify). To cleanly redeploy a starr I've left a Context.reify stub in sources, but hidden it behind a `protected` modifier. When starr is redeployed (in a subsequent commit) the stub will be removed. I've also updated the tests to use c.universe.reify instead of c.reify. This will break some of them, because c.universe.reify uses a standard compiler mirror, which unlike a macro mirror doesn't like packageless classes. That's an annoyance, but I think having clean separation of commits is more important that being 100% consistent. --- test/files/run/macro-openmacros/Impls_Macros_1.scala | 2 +- test/files/run/macro-reify-basic/Macros_1.scala | 2 +- test/files/run/macro-reify-freevars/Macros_1.scala | 2 +- test/files/run/macro-reify-nested-a/Impls_Macros_1.scala | 2 +- test/files/run/macro-reify-nested-b/Impls_Macros_1.scala | 2 +- test/files/run/macro-reify-ref-to-packageless/Impls_1.scala | 2 +- test/files/run/macro-reify-splice-splice/Macros_1.scala | 4 ++-- test/files/run/macro-reify-tagful-a/Macros_1.scala | 2 +- test/files/run/macro-reify-tagless-a/Impls_Macros_1.scala | 2 +- test/files/run/macro-reify-unreify/Macros_1.scala | 2 +- test/files/run/macro-settings/Impls_Macros_1.scala | 2 +- test/files/run/macro-sip19-revised/Impls_Macros_1.scala | 2 +- test/files/run/macro-sip19/Impls_Macros_1.scala | 2 +- test/files/run/macro-undetparams-consfromsls/Impls_Macros_1.scala | 4 ++-- test/files/run/macro-undetparams-macroitself/Impls_Macros_1.scala | 2 +- test/files/run/t5713/Impls_Macros_1.scala | 6 +++--- 16 files changed, 20 insertions(+), 20 deletions(-) (limited to 'test/files/run') diff --git a/test/files/run/macro-openmacros/Impls_Macros_1.scala b/test/files/run/macro-openmacros/Impls_Macros_1.scala index ffeccce1e8..6b92834b81 100644 --- a/test/files/run/macro-openmacros/Impls_Macros_1.scala +++ b/test/files/run/macro-openmacros/Impls_Macros_1.scala @@ -16,7 +16,7 @@ object Macros { import c.universe._ val next = if (c.enclosingMacros.length < 3) c.Expr[Unit](Select(Ident(c.mirror.staticModule("Macros")), newTermName("foo"))) else c.literalUnit - c.reify { + c.universe.reify { println(c.literal(normalizePaths(c.enclosingMacros.toString)).splice) next.splice } diff --git a/test/files/run/macro-reify-basic/Macros_1.scala b/test/files/run/macro-reify-basic/Macros_1.scala index 7a43ee58be..8f8598e248 100644 --- a/test/files/run/macro-reify-basic/Macros_1.scala +++ b/test/files/run/macro-reify-basic/Macros_1.scala @@ -4,7 +4,7 @@ object Macros { def foo(s: String) = macro Impls.foo object Impls { - def foo(c: Ctx)(s: c.Expr[String]) = c.reify { + def foo(c: Ctx)(s: c.Expr[String]) = c.universe.reify { println("hello " + s.splice) } } diff --git a/test/files/run/macro-reify-freevars/Macros_1.scala b/test/files/run/macro-reify-freevars/Macros_1.scala index eafc7f9a82..df1473511d 100644 --- a/test/files/run/macro-reify-freevars/Macros_1.scala +++ b/test/files/run/macro-reify-freevars/Macros_1.scala @@ -7,7 +7,7 @@ object QueryableMacros{ : c.Expr[scala.collection.slick.Queryable[S]] = { import c.universe._ val code = EmptyTree - c.reify{ + c.universe.reify{ Queryable.factory[S]( code.asInstanceOf[reflect.runtime.universe.Tree] ) } } diff --git a/test/files/run/macro-reify-nested-a/Impls_Macros_1.scala b/test/files/run/macro-reify-nested-a/Impls_Macros_1.scala index f9a08df90d..b52b962e31 100644 --- a/test/files/run/macro-reify-nested-a/Impls_Macros_1.scala +++ b/test/files/run/macro-reify-nested-a/Impls_Macros_1.scala @@ -30,7 +30,7 @@ object QueryableMacros{ Apply(Select(c.prefix.tree, newTermName( name )), List( projection.tree )) ).asInstanceOf[Tree] ))) - c.reify{ Queryable.factory[S]( foo.splice )} + c.universe.reify{ Queryable.factory[S]( foo.splice )} } def map[T:c.TypeTag, S:c.TypeTag] (c: scala.reflect.makro.Context) diff --git a/test/files/run/macro-reify-nested-b/Impls_Macros_1.scala b/test/files/run/macro-reify-nested-b/Impls_Macros_1.scala index f9a08df90d..b52b962e31 100644 --- a/test/files/run/macro-reify-nested-b/Impls_Macros_1.scala +++ b/test/files/run/macro-reify-nested-b/Impls_Macros_1.scala @@ -30,7 +30,7 @@ object QueryableMacros{ Apply(Select(c.prefix.tree, newTermName( name )), List( projection.tree )) ).asInstanceOf[Tree] ))) - c.reify{ Queryable.factory[S]( foo.splice )} + c.universe.reify{ Queryable.factory[S]( foo.splice )} } def map[T:c.TypeTag, S:c.TypeTag] (c: scala.reflect.makro.Context) diff --git a/test/files/run/macro-reify-ref-to-packageless/Impls_1.scala b/test/files/run/macro-reify-ref-to-packageless/Impls_1.scala index 2f2d05678d..66c0ee1e9b 100644 --- a/test/files/run/macro-reify-ref-to-packageless/Impls_1.scala +++ b/test/files/run/macro-reify-ref-to-packageless/Impls_1.scala @@ -2,5 +2,5 @@ import scala.reflect.makro.{Context => Ctx} object Impls { val `Answer to the Ultimate Question of Life, the Universe, and Everything` = 42 - def foo(c: Ctx) = c.reify { `Answer to the Ultimate Question of Life, the Universe, and Everything` } + def foo(c: Ctx) = c.universe.reify { `Answer to the Ultimate Question of Life, the Universe, and Everything` } } diff --git a/test/files/run/macro-reify-splice-splice/Macros_1.scala b/test/files/run/macro-reify-splice-splice/Macros_1.scala index 4f1b600f63..0de780b5a2 100644 --- a/test/files/run/macro-reify-splice-splice/Macros_1.scala +++ b/test/files/run/macro-reify-splice-splice/Macros_1.scala @@ -4,8 +4,8 @@ object Macros { def foo = macro Impls.foo object Impls { - def foo(c: Ctx) = c.reify { - { c.reify(c.reify("hello world")) }.splice.splice + def foo(c: Ctx) = c.universe.reify { + { c.universe.reify(c.universe.reify("hello world")) }.splice.splice } } } \ No newline at end of file diff --git a/test/files/run/macro-reify-tagful-a/Macros_1.scala b/test/files/run/macro-reify-tagful-a/Macros_1.scala index 63f117220a..32b09bdcdf 100644 --- a/test/files/run/macro-reify-tagful-a/Macros_1.scala +++ b/test/files/run/macro-reify-tagful-a/Macros_1.scala @@ -5,7 +5,7 @@ object Macros { def foo[T](s: T) = macro Impls.foo[T] object Impls { - def foo[T: c.TypeTag](c: Ctx)(s: c.Expr[T]) = c.reify { + def foo[T: c.TypeTag](c: Ctx)(s: c.Expr[T]) = c.universe.reify { List(s.splice) } } diff --git a/test/files/run/macro-reify-tagless-a/Impls_Macros_1.scala b/test/files/run/macro-reify-tagless-a/Impls_Macros_1.scala index 3796ae99cb..77e4b729d3 100644 --- a/test/files/run/macro-reify-tagless-a/Impls_Macros_1.scala +++ b/test/files/run/macro-reify-tagless-a/Impls_Macros_1.scala @@ -4,7 +4,7 @@ object Macros { def foo[T](s: T) = macro Impls.foo[T] object Impls { - def foo[T](c: Ctx)(s: c.Expr[T]) = c.reify { + def foo[T](c: Ctx)(s: c.Expr[T]) = c.universe.reify { List[T](s.splice) } } diff --git a/test/files/run/macro-reify-unreify/Macros_1.scala b/test/files/run/macro-reify-unreify/Macros_1.scala index 14777506d3..3e9033966d 100644 --- a/test/files/run/macro-reify-unreify/Macros_1.scala +++ b/test/files/run/macro-reify-unreify/Macros_1.scala @@ -11,7 +11,7 @@ object Macros { val greeting = c.reifyTree(c.runtimeUniverse, EmptyTree, c.typeCheck(Apply(Select(Literal(Constant("hello ")), newTermName("$plus")), List(c.unreifyTree(world))))) val typedGreeting = c.Expr[String](greeting) - c.reify { + c.universe.reify { println("hello " + s.splice + " = " + typedGreeting.splice) } } diff --git a/test/files/run/macro-settings/Impls_Macros_1.scala b/test/files/run/macro-settings/Impls_Macros_1.scala index 56e28b506c..20dcdc1bd1 100644 --- a/test/files/run/macro-settings/Impls_Macros_1.scala +++ b/test/files/run/macro-settings/Impls_Macros_1.scala @@ -1,7 +1,7 @@ import scala.reflect.makro.Context object Impls { - def impl(c: Context) = c.reify { + def impl(c: Context) = c.universe.reify { println(c.literal(c.settings.toString).splice) } } diff --git a/test/files/run/macro-sip19-revised/Impls_Macros_1.scala b/test/files/run/macro-sip19-revised/Impls_Macros_1.scala index 994421808e..013130d181 100644 --- a/test/files/run/macro-sip19-revised/Impls_Macros_1.scala +++ b/test/files/run/macro-sip19-revised/Impls_Macros_1.scala @@ -11,7 +11,7 @@ object Macros { val fileName = fun.pos.fileInfo.getName val line = fun.pos.line val charOffset = fun.pos.point - c.reify { SourceLocation1(outer.splice, c.literal(fileName).splice, c.literal(line).splice, c.literal(charOffset).splice) } + c.universe.reify { SourceLocation1(outer.splice, c.literal(fileName).splice, c.literal(line).splice, c.literal(charOffset).splice) } } implicit def sourceLocation: SourceLocation1 = macro impl diff --git a/test/files/run/macro-sip19/Impls_Macros_1.scala b/test/files/run/macro-sip19/Impls_Macros_1.scala index c006ceb691..f6636c298c 100644 --- a/test/files/run/macro-sip19/Impls_Macros_1.scala +++ b/test/files/run/macro-sip19/Impls_Macros_1.scala @@ -7,7 +7,7 @@ object Macros { val fileName = fun.pos.fileInfo.getName val line = fun.pos.line val charOffset = fun.pos.point - c.reify { SourceLocation(c.literal(fileName).splice, c.literal(line).splice, c.literal(charOffset).splice) } + c.universe.reify { SourceLocation(c.literal(fileName).splice, c.literal(line).splice, c.literal(charOffset).splice) } } implicit def sourceLocation: SourceLocation = macro impl diff --git a/test/files/run/macro-undetparams-consfromsls/Impls_Macros_1.scala b/test/files/run/macro-undetparams-consfromsls/Impls_Macros_1.scala index b9bb2cfcca..7b921c0e57 100644 --- a/test/files/run/macro-undetparams-consfromsls/Impls_Macros_1.scala +++ b/test/files/run/macro-undetparams-consfromsls/Impls_Macros_1.scala @@ -2,12 +2,12 @@ import scala.reflect.runtime.universe._ import scala.reflect.makro.Context object Macros { - def cons_impl[A: c.AbsTypeTag](c: Context)(x: c.Expr[A], xs: c.Expr[List[A]]): c.Expr[List[A]] = c.reify { + def cons_impl[A: c.AbsTypeTag](c: Context)(x: c.Expr[A], xs: c.Expr[List[A]]): c.Expr[List[A]] = c.universe.reify { println("A = " + c.literal(implicitly[c.AbsTypeTag[A]].toString).splice) x.splice :: xs.splice } - def nil_impl[B: c.AbsTypeTag](c: Context): c.Expr[List[B]] = c.reify { + def nil_impl[B: c.AbsTypeTag](c: Context): c.Expr[List[B]] = c.universe.reify { println("B = " + c.literal(implicitly[c.AbsTypeTag[B]].toString).splice) Nil } diff --git a/test/files/run/macro-undetparams-macroitself/Impls_Macros_1.scala b/test/files/run/macro-undetparams-macroitself/Impls_Macros_1.scala index 9b1dd8e017..fdba40623b 100644 --- a/test/files/run/macro-undetparams-macroitself/Impls_Macros_1.scala +++ b/test/files/run/macro-undetparams-macroitself/Impls_Macros_1.scala @@ -2,7 +2,7 @@ import scala.reflect.runtime.universe._ import scala.reflect.makro.Context object Macros { - def impl[T: c.TypeTag](c: Context)(foo: c.Expr[T]): c.Expr[Unit] = c.reify { println(c.literal(implicitly[c.TypeTag[T]].toString).splice) } + def impl[T: c.TypeTag](c: Context)(foo: c.Expr[T]): c.Expr[Unit] = c.universe.reify { println(c.literal(implicitly[c.TypeTag[T]].toString).splice) } def foo[T](foo: T) = macro impl[T] } \ No newline at end of file diff --git a/test/files/run/t5713/Impls_Macros_1.scala b/test/files/run/t5713/Impls_Macros_1.scala index d16299a0c8..c041d36523 100644 --- a/test/files/run/t5713/Impls_Macros_1.scala +++ b/test/files/run/t5713/Impls_Macros_1.scala @@ -16,13 +16,13 @@ private object LoggerMacros { type LoggerContext = Context { type PrefixType = Logger.type } def error(c: LoggerContext)(message: c.Expr[String]): c.Expr[Unit] = - log(c)(c.reify(Level.Error), message) + log(c)(c.universe.reify(Level.Error), message) private def log(c: LoggerContext)(level: c.Expr[Level.Value], message: c.Expr[String]): c.Expr[Unit] = // was: if (level.splice.id < 4) // TODO Remove hack! if (c.eval(level).id < 4) // TODO Remove hack! - c.reify(()) + c.universe.reify(()) else { - c.reify(println(message.splice)) + c.universe.reify(println(message.splice)) } } \ No newline at end of file -- cgit v1.2.3 From b5f721fb52767d0b839a0ef4614d1bcb039adba1 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 20 Jul 2012 12:46:05 +0200 Subject: 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. --- .../scala/reflect/reify/codegen/GenSymbols.scala | 36 +++++++- .../scala/reflect/reify/codegen/GenTypes.scala | 3 +- .../scala/reflect/reify/utils/Extractors.scala | 4 +- .../plugin/scala/tools/selectivecps/CPSUtils.scala | 2 +- src/library/scala/reflect/base/Base.scala | 3 + src/library/scala/reflect/base/MirrorOf.scala | 49 ++++++++++- src/partest/scala/tools/partest/CompilerTest.scala | 2 +- src/reflect/scala/reflect/internal/Mirrors.scala | 99 +++++++++++++--------- src/reflect/scala/reflect/internal/StdNames.scala | 1 + .../scala/reflect/runtime/JavaMirrors.scala | 12 +++ test/files/run/existentials-in-compiler.scala | 2 +- test/files/run/macro-reify-staticXXX.check | 12 +++ test/files/run/macro-reify-staticXXX.flags | 1 + .../files/run/macro-reify-staticXXX/Macros_1.scala | 48 +++++++++++ test/files/run/macro-reify-staticXXX/Test_2.scala | 4 + .../run/macro-typecheck-macrosdisabled2.check | 4 +- test/files/run/reify-staticXXX.check | 24 ++++++ test/files/run/reify-staticXXX.scala | 56 ++++++++++++ .../run/toolbox_typecheck_macrosdisabled2.check | 4 +- 19 files changed, 310 insertions(+), 56 deletions(-) create mode 100644 test/files/run/macro-reify-staticXXX.check create mode 100644 test/files/run/macro-reify-staticXXX.flags create mode 100644 test/files/run/macro-reify-staticXXX/Macros_1.scala create mode 100644 test/files/run/macro-reify-staticXXX/Test_2.scala create mode 100644 test/files/run/reify-staticXXX.check create mode 100644 test/files/run/reify-staticXXX.scala (limited to 'test/files/run') 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/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 d030ace96c..6dc8090eee 100644 --- a/src/library/scala/reflect/base/MirrorOf.scala +++ b/src/library/scala/reflect/base/MirrorOf.scala @@ -25,7 +25,7 @@ abstract class MirrorOf[U <: base.Universe with Singleton] { * scala> res0.fullName * res1: String = scala.collection.immutable.List * - * scala> cm.staticModule("scala") + * scala> cm.staticPackage("scala") * res2: reflect.runtime.universe.ModuleSymbol = package scala * * scala> res2.moduleClass.typeSignature member newTypeName("List") @@ -33,11 +33,58 @@ abstract class MirrorOf[U <: base.Universe with Singleton] { * * 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/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? diff --git a/test/files/run/existentials-in-compiler.scala b/test/files/run/existentials-in-compiler.scala index 1f314aa4e0..c69d1217fd 100644 --- a/test/files/run/existentials-in-compiler.scala +++ b/test/files/run/existentials-in-compiler.scala @@ -72,7 +72,7 @@ package extest { """ def check(source: String, unit: global.CompilationUnit) = { - getRequiredModule("extest").moduleClass.info.decls.toList.filter(_.isType).map(_.initialize).sortBy(_.name.toString) foreach { clazz => + getRequiredPackage("extest").moduleClass.info.decls.toList.filter(_.isType).map(_.initialize).sortBy(_.name.toString) foreach { clazz => afterTyper { clazz.info println(clazz.defString) diff --git a/test/files/run/macro-reify-staticXXX.check b/test/files/run/macro-reify-staticXXX.check new file mode 100644 index 0000000000..2894fa5843 --- /dev/null +++ b/test/files/run/macro-reify-staticXXX.check @@ -0,0 +1,12 @@ +object +class +object > object +object > class +package > object +package > class +object +class +object > object +object > class +package > object +package > class \ No newline at end of file diff --git a/test/files/run/macro-reify-staticXXX.flags b/test/files/run/macro-reify-staticXXX.flags new file mode 100644 index 0000000000..cd66464f2f --- /dev/null +++ b/test/files/run/macro-reify-staticXXX.flags @@ -0,0 +1 @@ +-language:experimental.macros \ No newline at end of file diff --git a/test/files/run/macro-reify-staticXXX/Macros_1.scala b/test/files/run/macro-reify-staticXXX/Macros_1.scala new file mode 100644 index 0000000000..b0ce6507f8 --- /dev/null +++ b/test/files/run/macro-reify-staticXXX/Macros_1.scala @@ -0,0 +1,48 @@ +import scala.reflect.makro.Context + +object B { override def toString = "object" } +class C { override def toString = "class" } + +package foo { + object B { override def toString = "package > object" } + class C { override def toString = "package > class" } +} + +object foo { + object B { override def toString = "object > object" } + class C { override def toString = "object > class" } +} + +object packageless { + def impl(c: Context) = { + import c.universe._ + reify { + println(B) + println(new C) + println(foo.B) + println(new foo.C) + println(_root_.foo.B) + println(new _root_.foo.C) + } + } + + def test = macro impl +} + +package packageful { + object Test { + def impl(c: Context) = { + import c.universe._ + reify { + println(B) + println(new C) + println(foo.B) + println(new foo.C) + println(_root_.foo.B) + println(new _root_.foo.C) + } + } + + def test = macro impl + } +} diff --git a/test/files/run/macro-reify-staticXXX/Test_2.scala b/test/files/run/macro-reify-staticXXX/Test_2.scala new file mode 100644 index 0000000000..6e8cc36080 --- /dev/null +++ b/test/files/run/macro-reify-staticXXX/Test_2.scala @@ -0,0 +1,4 @@ +object Test extends App { + packageless.test + packageful.Test.test +} diff --git a/test/files/run/macro-typecheck-macrosdisabled2.check b/test/files/run/macro-typecheck-macrosdisabled2.check index e440b2c0cb..2160d3800a 100644 --- a/test/files/run/macro-typecheck-macrosdisabled2.check +++ b/test/files/run/macro-typecheck-macrosdisabled2.check @@ -15,7 +15,7 @@ private def applyImpl[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.base.MirrorOf[U]): scala.reflect.base.Universe#Tree = { val $u: U = $m$untyped.universe; val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror]; - $u.Apply.apply($u.Select.apply($u.Select.apply($u.build.Ident($m.staticModule("scala")), $u.newTermName("Array")), $u.newTermName("apply")), scala.collection.immutable.List.apply[$u.Literal]($u.Literal.apply($u.Constant.apply(2)))) + $u.Apply.apply($u.Select.apply($u.Select.apply($u.build.Ident($m.staticPackage("scala")), $u.newTermName("Array")), $u.newTermName("apply")), scala.collection.immutable.List.apply[$u.Literal]($u.Literal.apply($u.Constant.apply(2)))) } }; new $treecreator1() @@ -28,7 +28,7 @@ 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.apply($u.ThisType.apply($m.staticModule("scala").asModuleSymbol.moduleClass), $m.staticClass("scala.Array"), scala.collection.immutable.List.apply[$u.Type]($m.staticClass("scala.Int").asTypeSymbol.asTypeConstructor)) + $u.TypeRef.apply($u.ThisType.apply($m.staticPackage("scala").asModuleSymbol.moduleClass), $m.staticClass("scala.Array"), scala.collection.immutable.List.apply[$u.Type]($m.staticClass("scala.Int").asTypeSymbol.asTypeConstructor)) } }; new $typecreator2() diff --git a/test/files/run/reify-staticXXX.check b/test/files/run/reify-staticXXX.check new file mode 100644 index 0000000000..5762ec47d6 --- /dev/null +++ b/test/files/run/reify-staticXXX.check @@ -0,0 +1,24 @@ +object +object +class +class +object > object +object > object +object > class +object > class +package > object +package > object +package > class +package > class +object +object +class +class +object > object +object > object +object > class +object > class +package > object +package > object +package > class +package > class diff --git a/test/files/run/reify-staticXXX.scala b/test/files/run/reify-staticXXX.scala new file mode 100644 index 0000000000..dc861f843e --- /dev/null +++ b/test/files/run/reify-staticXXX.scala @@ -0,0 +1,56 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.Eval + +object B { override def toString = "object" } +class C { override def toString = "class" } + +package foo { + object B { override def toString = "package > object" } + class C { override def toString = "package > class" } +} + +object foo { + object B { override def toString = "object > object" } + class C { override def toString = "object > class" } +} + +object packageless { + def test = { + println(B) + println(reify(B).eval) + println(new C) + println(reify(new C).eval) + println(foo.B) + println(reify(foo.B).eval) + println(new foo.C) + println(reify(new foo.C).eval) + println(_root_.foo.B) + println(reify(_root_.foo.B).eval) + println(new _root_.foo.C) + println(reify(new _root_.foo.C).eval) + } +} + +package packageful { + object Test { + def test = { + println(B) + println(reify(B).eval) + println(new C) + println(reify(new C).eval) + println(foo.B) + println(reify(foo.B).eval) + println(new foo.C) + println(reify(new foo.C).eval) + println(_root_.foo.B) + println(reify(_root_.foo.B).eval) + println(new _root_.foo.C) + println(reify(new _root_.foo.C).eval) + } + } +} + +object Test extends App { + packageless.test + packageful.Test.test +} diff --git a/test/files/run/toolbox_typecheck_macrosdisabled2.check b/test/files/run/toolbox_typecheck_macrosdisabled2.check index 2e1e2696ab..53041e328d 100644 --- a/test/files/run/toolbox_typecheck_macrosdisabled2.check +++ b/test/files/run/toolbox_typecheck_macrosdisabled2.check @@ -15,7 +15,7 @@ private def applyImpl[U <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.base.MirrorOf[U]): scala.reflect.base.Universe#Tree = { val $u: U = $m$untyped.universe; val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror]; - $u.Apply.apply($u.Select.apply($u.Select.apply($u.build.Ident($m.staticModule("scala")), $u.newTermName("Array")), $u.newTermName("apply")), scala.collection.immutable.List.apply[$u.Literal]($u.Literal.apply($u.Constant.apply(2)))) + $u.Apply.apply($u.Select.apply($u.Select.apply($u.build.Ident($m.staticPackage("scala")), $u.newTermName("Array")), $u.newTermName("apply")), scala.collection.immutable.List.apply[$u.Literal]($u.Literal.apply($u.Constant.apply(2)))) } }; new $treecreator1() @@ -28,7 +28,7 @@ def apply[U <: 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.apply($u.ThisType.apply($m.staticModule("scala").asModuleSymbol.moduleClass), $m.staticClass("scala.Array"), scala.collection.immutable.List.apply[$u.Type]($m.staticClass("scala.Int").asTypeSymbol.asTypeConstructor)) + $u.TypeRef.apply($u.ThisType.apply($m.staticPackage("scala").asModuleSymbol.moduleClass), $m.staticClass("scala.Array"), scala.collection.immutable.List.apply[$u.Type]($m.staticClass("scala.Int").asTypeSymbol.asTypeConstructor)) } }; new $typecreator2() -- cgit v1.2.3