mirror of https://github.com/sbt/sbt.git
Merge pull request #1019 from gkossakowski/scala-2.11-compat
Make incremental compiler compatible with Scala 2.11.
This commit is contained in:
commit
cbd57040ad
|
|
@ -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
|
||||
{
|
||||
|
|
@ -39,10 +70,13 @@ abstract class Compat
|
|||
def unapply(t: Type): Option[Type] = None
|
||||
}
|
||||
|
||||
// before 2.10, sym.moduleSuffix doesn't exist, but genJVM.moduleSuffix does
|
||||
private[this] implicit def symbolCompat(sym: Symbol): SymbolCompat = new SymbolCompat(sym)
|
||||
private[this] final class SymbolCompat(sym: Symbol) {
|
||||
protected implicit def symbolCompat(sym: Symbol): SymbolCompat = new SymbolCompat(sym)
|
||||
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
|
||||
def toplevelClass: Symbol = sourceCompatibilityOnly
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -156,9 +156,7 @@ final class Dependency(val global: CallbackGlobal) extends LocateClassFile
|
|||
val traverser = new ExtractDependenciesByMemberRefTraverser
|
||||
traverser.traverse(unit.body)
|
||||
val dependencies = traverser.dependencies
|
||||
// we capture enclosing classes only because that's what CompilationUnit.depends does and we don't want
|
||||
// to deviate from old behaviour too much for now
|
||||
dependencies.map(_.toplevelClass)
|
||||
dependencies.map(enclosingTopLevelClass)
|
||||
}
|
||||
|
||||
/** Copied straight from Scala 2.10 as it does not exist in Scala 2.9 compiler */
|
||||
|
|
@ -184,7 +182,15 @@ final class Dependency(val global: CallbackGlobal) extends LocateClassFile
|
|||
val traverser = new ExtractDependenciesByInheritanceTraverser
|
||||
traverser.traverse(unit.body)
|
||||
val dependencies = traverser.dependencies
|
||||
dependencies.map(_.toplevelClass)
|
||||
dependencies.map(enclosingTopLevelClass)
|
||||
}
|
||||
|
||||
/**
|
||||
* We capture enclosing classes only because that's what CompilationUnit.depends does and we don't want
|
||||
* to deviate from old behaviour too much for now.
|
||||
*/
|
||||
private def enclosingTopLevelClass(sym: Symbol): Symbol =
|
||||
// for Scala 2.8 and 2.9 this method is provided through SymbolCompat
|
||||
sym.enclosingTopLevelClass
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue