summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/AddInterfaces.scala')
-rw-r--r--src/compiler/scala/tools/nsc/transform/AddInterfaces.scala133
1 files changed, 71 insertions, 62 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
index 39e2cbe694..3581f1b923 100644
--- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
+++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
@@ -43,11 +43,7 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
*/
private def isInterfaceMember(sym: Symbol) = (
sym.isType || {
- // !!! Shouldn't the following code be equivalent to leaving
- // out the "sym.info" call and starting with "sym.initialize.isMethod" ?
- // Because, it is not, which I found a little disturbing. The compiler
- // fails to bootstrap with an error somewhere.
- sym.info // initialize to set lateMETHOD flag if necessary
+ sym.info // initialize to set lateMETHOD flag if necessary
( sym.isMethod
&& !sym.isLabel
@@ -68,57 +64,60 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
def implClassPhase = currentRun.erasurePhase.next
- /** Return the implementation class of a trait; create a new one of one does not yet exist */
- def implClass(iface: Symbol): Symbol = {
- iface.info
-
- implClassMap.getOrElse(iface, {
- atPhase(implClassPhase) {
- if (iface.implClass ne NoSymbol)
- log("%s.implClass == %s".format(iface, iface.implClass))
+ private def newImplClass(iface: Symbol): Symbol = {
+ val inClass = iface.owner.isClass
+ val implName = tpnme.implClassName(iface.name)
+ val implFlags = (iface.flags & ~(INTERFACE | lateINTERFACE)) | IMPLCLASS
- val implName = nme.implClassName(iface.name)
- var impl = if (iface.owner.isClass) iface.owner.info.decl(implName) else NoSymbol
-
- // !!! Why does forcing the impl's info here lead to a crash?
- // See test case pos/trait-force-info.scala for a minimization.
- // It crashes like this:
- //
- // [log lazyvals] trait ContextTrees.implClass == class ContextTrees$class
- // error: java.lang.AssertionError: assertion failed: (scala.tools.nsc.typechecker.Contexts$NoContext$,scala.tools.nsc.typechecker.Contexts,NoContext$,trait Contexts in package typechecker) / while parsing (/scala/trunk/build/pack/lib/scala-compiler.jar(scala/tools/nsc/interactive/ContextTrees$class.class),Some(class ContextTrees$class))trait Contexts.NoContext$ linkedModule: <none>List()
-
- val originalImpl = impl
- if (impl != NoSymbol) {
+ val impl0 = (
+ if (!inClass) NoSymbol
+ else iface.owner.info.decl(implName) match {
+ case NoSymbol => NoSymbol
+ case implSym =>
// Unlink a pre-existing symbol only if the implementation class is
// visible on the compilation classpath. In general this is true under
// -optimise and not otherwise, but the classpath can use arbitrary
// logic so the classpath must be queried.
if (classPath.context.isValidName(implName + ".class")) {
- log("unlinking impl class " + impl)
- iface.owner.info.decls.unlink(impl)
- impl = NoSymbol
+ log("unlinking impl class " + implSym)
+ iface.owner.info.decls unlink implSym
+ NoSymbol
+ }
+ else {
+ log("not unlinking existing " + implSym + " as the impl class is not visible on the classpath.")
+ implSym
}
- else log("not unlinking existing " + impl + " as the impl class is not visible on the classpath.")
- }
- if (impl == NoSymbol) {
- impl = iface.cloneSymbolImpl(iface.owner)
- impl.name = implName
- impl.sourceFile = iface.sourceFile
- if (iface.owner.isClass)
- iface.owner.info.decls enter impl
- }
- if (currentRun.compiles(iface)) currentRun.symSource(impl) = iface.sourceFile
- impl setPos iface.pos
- impl.flags = iface.flags & ~(INTERFACE | lateINTERFACE) | IMPLCLASS
- impl setInfo new LazyImplClassType(iface)
- implClassMap(iface) = impl
- debuglog(
- "generating impl class " + impl.debugLocationString + " in " + iface.owner + (
- if (originalImpl == NoSymbol) "" else " (cloned from " + originalImpl.debugLocationString + ")"
- )
- )
- impl
}
+ )
+ val impl = impl0 orElse {
+ val impl = iface.owner.newImplClass(implName, iface.pos, implFlags)
+ if (iface.thisSym != iface) {
+ impl.typeOfThis = iface.typeOfThis
+ impl.thisSym setName iface.thisSym.name
+ }
+ impl.sourceFile = iface.sourceFile
+ if (inClass)
+ iface.owner.info.decls enter impl
+
+ impl
+ }
+ if (currentRun compiles iface)
+ currentRun.symSource(impl) = iface.sourceFile
+
+ implClassMap(iface) = impl
+ impl setInfo new LazyImplClassType(iface)
+ }
+
+ /** Return the implementation class of a trait; create a new one of one does not yet exist */
+ def implClass(iface: Symbol): Symbol = {
+ iface.info
+
+ implClassMap.getOrElse(iface, atPhase(implClassPhase) {
+ log("Creating implClass for " + iface)
+ if (iface.implClass ne NoSymbol)
+ log("%s.implClass already exists: %s".format(iface, iface.implClass))
+
+ newImplClass(iface)
})
}
@@ -138,22 +137,31 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
* given the decls ifaceDecls of its interface.
*/
private def implDecls(implClass: Symbol, ifaceDecls: Scope): Scope = {
+ log("LazyImplClassType calculating decls for " + implClass)
+
val decls = newScope
- if ((ifaceDecls lookup nme.MIXIN_CONSTRUCTOR) == NoSymbol)
+ if ((ifaceDecls lookup nme.MIXIN_CONSTRUCTOR) == NoSymbol) {
+ log("Adding mixin constructor to " + implClass)
+
decls enter (
implClass.newMethod(nme.MIXIN_CONSTRUCTOR, implClass.pos)
setInfo MethodType(Nil, UnitClass.tpe)
)
+ }
- for (sym <- ifaceDecls.iterator) {
+ for (sym <- ifaceDecls) {
if (isInterfaceMember(sym)) {
if (needsImplMethod(sym)) {
- val impl = sym.cloneSymbol(implClass).resetFlag(lateDEFERRED)
- if (currentRun.compiles(implClass)) implMethodMap(sym) = impl
- decls enter impl
+ log("Cloning " + sym + " for implementation method in " + implClass)
+ val clone = sym.cloneSymbol(implClass).resetFlag(lateDEFERRED)
+ if (currentRun.compiles(implClass)) implMethodMap(sym) = clone
+ decls enter clone
sym setFlag lateDEFERRED
}
- } else {
+ else log(sym + " needs no implementation method in " + implClass)
+ }
+ else {
+ log("Destructively modifying owner of %s from %s to %s".format(sym, sym.owner, implClass))
sym.owner = implClass
// note: OK to destructively modify the owner here,
// because symbol will not be accessible from outside the sourcefile.
@@ -161,14 +169,17 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
decls enter sym
}
}
+
decls
}
- override def complete(sym: Symbol) {
+ override def complete(implSym: Symbol) {
+ log("LazyImplClassType completing " + implSym)
+
/** If `tp` refers to a non-interface trait, return a
* reference to its implementation class. Otherwise return `tp`.
*/
- def mixinToImplClass(tp: Type): Type = erasure(sym) {
+ def mixinToImplClass(tp: Type): Type = AddInterfaces.this.erasure(implSym) {
tp match { //@MATN: no normalize needed (comes after erasure)
case TypeRef(pre, sym, _) if sym.needsImplClass =>
typeRef(pre, implClass(sym), Nil)
@@ -179,15 +190,13 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
def implType(tp: Type): Type = tp match {
case ClassInfoType(parents, decls, _) =>
assert(phase == implClassPhase, tp)
- ClassInfoType(
- ObjectClass.tpe +: (parents.tail map mixinToImplClass filter (_.typeSymbol != ObjectClass)) :+ iface.tpe,
- implDecls(sym, decls),
- sym
- )
+ // Impl class parents: Object first, matching interface last.
+ val implParents = ObjectClass.tpe +: (parents.tail map mixinToImplClass filter (_.typeSymbol != ObjectClass)) :+ iface.tpe
+ ClassInfoType(implParents, implDecls(implSym, decls), implSym)
case PolyType(_, restpe) =>
implType(restpe)
}
- sym setInfo implType(beforeErasure(iface.info))
+ implSym setInfo implType(beforeErasure(iface.info))
}
override def load(clazz: Symbol) { complete(clazz) }