diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2012-12-25 02:37:31 +0100 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2013-01-05 01:39:15 +0300 |
commit | 348c8fac9f897f9661f84e32949b8a4e0c99e93a (patch) | |
tree | 810b2d7d53451ceba5e43e1687a86cdedffd39f1 /src/compiler/scala/tools/nsc/CompilationUnits.scala | |
parent | ed4f4798df2ac104d9557de2241d8e89283b0662 (diff) | |
download | scala-348c8fac9f897f9661f84e32949b8a4e0c99e93a.tar.gz scala-348c8fac9f897f9661f84e32949b8a4e0c99e93a.tar.bz2 scala-348c8fac9f897f9661f84e32949b8a4e0c99e93a.zip |
adds c.introduceTopLevel
The first in the family of mutators for the global symbol table,
`introduceTopLevel` is capable of creating synthetic top-level
classes and modules.
The addition of nme.EMPTY_PACKAGE_NAME is necessary to let
programmers insert definitions into the empty package. That's explicitly
discouraged in the docs, but at times might come in handy.
This patch introduce workarounds to avoid incompatibilities with SBT.
First of all SBT doesn't like VirtualFiles having JFile set to null.
Secondly SBT gets confused when someone depends on synthetic files
added by c.introduceTopLevel.
Strictly speaking these problems require changes to SBT, and that will be
done later. However the main target of the patch is paradise/macros,
which needs to be useful immediately, therefore we apply workarounds.
Diffstat (limited to 'src/compiler/scala/tools/nsc/CompilationUnits.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/CompilationUnits.scala | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index a2108b8ced..15d365ab8c 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -39,11 +39,31 @@ trait CompilationUnits { self: Global => /** Note: depends now contains toplevel classes. * To get their sourcefiles, you need to dereference with .sourcefile */ - val depends = mutable.HashSet[Symbol]() + private[this] val _depends = mutable.HashSet[Symbol]() + // SBT compatibility (SI-6875) + // + // imagine we have a file named A.scala, which defines a trait named Foo and a module named Main + // Main contains a call to a macro, which calls c.introduceTopLevel to define a mock for Foo + // c.introduceTopLevel creates a virtual file Virt35af32.scala, which contains a class named FooMock extending Foo, + // and macro expansion instantiates FooMock. the stage is now set. let's see what happens next. + // + // without this workaround in scalac or without being patched itself, sbt will think that + // * Virt35af32 depends on A (because it extends Foo from A) + // * A depends on Virt35af32 (because it contains a macro expansion referring to FooMock from Virt35af32) + // + // after compiling A.scala, SBT will notice that it has a new source file named Virt35af32. + // it will also think that this file hasn't yet been compiled and since A depends on it + // it will think that A needs to be recompiled. + // + // recompilation will lead to another macro expansion. that another macro expansion might choose to create a fresh mock, + // producing another virtual file, say, Virtee509a, which will again trick SBT into thinking that A needs a recompile, + // which will lead to another macro expansion, which will produce another virtual file and so on + def depends = if (exists && !source.file.isVirtual) _depends else mutable.HashSet[Symbol]() /** so we can relink */ - val defined = mutable.HashSet[Symbol]() + private[this] val _defined = mutable.HashSet[Symbol]() + def defined = if (exists && !source.file.isVirtual) _defined else mutable.HashSet[Symbol]() /** Synthetic definitions generated by namer, eliminated by typer. */ |