Add more documentation to Compat class in compiler interface.

Add documentation which explains how a general technique using implicits
conversions is employed in Compat class. Previously, it was hidden inside
of Compat class.

Also, I changed `toplevelClass` implementation to call
`sourceCompatibilityOnly` method that is designed for the purpose
of being a compatibility stub.
This commit is contained in:
Grzegorz Kossakowski 2013-12-02 17:55:11 +01:00
parent ff9dd6e9dd
commit 7e303f8692
1 changed files with 35 additions and 8 deletions

View File

@ -4,8 +4,39 @@ import scala.tools.nsc.Global
import scala.tools.nsc.symtab.Flags
/**
* Collection of hacks that make it possible for the compiler interface
* to stay source compatible with Scala compiler 2.9, 2.10 and 2.11.
* Collection of hacks that make it possible for the compiler interface
* to stay source compatible with Scala compiler 2.9, 2.10 and 2.11.
*
* One common technique used in `Compat` class is use of implicit conversions to deal
* with methods that got renamed or moved between different Scala compiler versions.
*
* Let's pick a specific example. In Scala 2.9 and 2.10 there was a method called `toplevelClass`
* defined on `Symbol`. In 2.10 that method has been deprecated and `enclosingTopLevelClass`
* method has been introduce as a replacement. In Scala 2.11 the old `toplevelClass` method has
* been removed. How can we pick the right version based on availability of those two methods?
*
* We define an implicit conversion from Symbol to a class that contains both method definitions:
*
* implicit def symbolCompat(sym: Symbol): SymbolCompat = new SymbolCompat(sym)
* class SymbolCompat(sym: Symbol) {
* def enclosingTopLevelClass: Symbol = sym.toplevelClass
* def toplevelClass: Symbol =
* throw new RuntimeException("For source compatibility only: should not get here.")
* }
*
* We assume that client code (code in compiler interface) should always call `enclosingTopLevelClass`
* method. If we compile that code against 2.11 it will just directly link against method provided by
* Symbol. However, if we compile against 2.9 or 2.10 `enclosingTopLevelClass` won't be found so the
* implicit conversion defined above will kick in. That conversion will provide `enclosingTopLevelClass`
* that simply forwards to the old `toplevelClass` method that is available in 2.9 and 2.10 so that
* method will be called in the end. There's one twist: since `enclosingTopLevelClass` forwards to
* `toplevelClass` which doesn't exist in 2.11! Therefore, we need to also define `toplevelClass`
* that will be provided by an implicit conversion as well. However, we should never reach that method
* at runtime if either `enclosingTopLevelClass` or `toplevelClass` is available on Symbol so this
* is purely source compatibility stub.
*
* The technique described above is used in several places below.
*
*/
abstract class Compat
{
@ -43,13 +74,9 @@ abstract class Compat
protected final class SymbolCompat(sym: Symbol) {
// before 2.10, sym.moduleSuffix doesn't exist, but genJVM.moduleSuffix does
def moduleSuffix = global.genJVM.moduleSuffix(sym)
def enclosingTopLevelClass: Symbol = sym.toplevelClass
// this for compatibility with Scala 2.11 where Symbol.enclosingTopLevelClass method exist
// so we won't be ever calling SymbolCompat.enclosingTopLevelClass but we need to compile
// it hence we need dummy forwarder target, the `toplevelClass` method defined
// in Scala 2.9 and 2.10 the `Symbol.toplevelClass` exists so the dummy forwarder target
// won't be used
def toplevelClass: Symbol = throw new UnsupportedOperationException("We should never have gotten here")
def toplevelClass: Symbol = sourceCompatibilityOnly
}