summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools')
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala1
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala57
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala48
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala15
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/AddInterfaces.scala307
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala18
-rw-r--r--src/compiler/scala/tools/nsc/transform/Delambdafy.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala3
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala25
-rw-r--r--src/compiler/scala/tools/nsc/transform/Flatten.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala53
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala341
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala7
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala4
20 files changed, 172 insertions, 727 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index 3167f87383..7edac76b91 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -145,6 +145,7 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
override def mkCast(tree: Tree, pt: Type): Tree = {
debuglog("casting " + tree + ":" + tree.tpe + " to " + pt + " at phase: " + phase)
assert(!tree.tpe.isInstanceOf[MethodType], tree)
+ assert(!pt.isInstanceOf[MethodType], tree)
assert(pt eq pt.normalize, tree +" : "+ debugString(pt) +" ~>"+ debugString(pt.normalize))
atPos(tree.pos) {
mkAsInstanceOf(tree, pt, any = !phase.next.erasedTypes, wrapInApply = isAtPhaseAfter(currentRun.uncurryPhase))
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
index 8a90eb9780..82aa3c65aa 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
@@ -535,6 +535,22 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
private def genApply(app: Apply, expectedType: BType): BType = {
var generatedType = expectedType
lineNumber(app)
+
+ def genSuperApply(hostClass: Symbol, fun: Symbol, args: List[Tree]) = {
+ // 'super' call: Note: since constructors are supposed to
+ // return an instance of what they construct, we have to take
+ // special care. On JVM they are 'void', and Scala forbids (syntactically)
+ // to call super constructors explicitly and/or use their 'returned' value.
+ // therefore, we can ignore this fact, and generate code that leaves nothing
+ // on the stack (contrary to what the type in the AST says).
+
+ val invokeStyle = InvokeStyle.Super
+ mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
+ genLoadArguments(args, paramTKs(app))
+ genCallMethod(fun, invokeStyle, app.pos, hostClass)
+ generatedType = methodBTypeFromSymbol(fun).returnType
+ }
+
app match {
case Apply(TypeApply(fun, targs), _) =>
@@ -582,19 +598,19 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
generatedType = genTypeApply()
- // 'super' call: Note: since constructors are supposed to
- // return an instance of what they construct, we have to take
- // special care. On JVM they are 'void', and Scala forbids (syntactically)
- // to call super constructors explicitly and/or use their 'returned' value.
- // therefore, we can ignore this fact, and generate code that leaves nothing
- // on the stack (contrary to what the type in the AST says).
- case Apply(fun @ Select(Super(_, _), _), args) =>
- val invokeStyle = InvokeStyle.Super
- // if (fun.symbol.isConstructor) Static(true) else SuperCall(mix);
- mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
- genLoadArguments(args, paramTKs(app))
- genCallMethod(fun.symbol, invokeStyle, app.pos)
- generatedType = methodBTypeFromSymbol(fun.symbol).returnType
+ case Apply(fun @ Select(Super(qual, mix), _), args) =>
+ val hostClass = qual.symbol.parentSymbols.filter(_.name == mix) match {
+ case Nil =>
+ // We get here for trees created by SuperSelect which use tpnme.EMPTY as the super qualifier
+ // Subsequent code uses the owner of fun.symbol to target the call.
+ null
+ case parent :: Nil=>
+ parent
+ case parents =>
+ devWarning("ambiguous parent class qualifier: " + qual.symbol.parentSymbols)
+ null
+ }
+ genSuperApply(hostClass, fun.symbol, args)
// 'new' constructor call: Note: since constructors are
// thought to return an instance of what they construct,
@@ -1050,19 +1066,26 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
hostSymbol.info ; methodOwner.info
def needsInterfaceCall(sym: Symbol) = (
- sym.isInterface
+ sym.isTraitOrInterface
|| sym.isJavaDefined && sym.isNonBottomSubClass(definitions.ClassfileAnnotationClass)
)
+ val isTraitCallToObjectMethod =
+ hostSymbol != methodOwner && methodOwner.isTraitOrInterface && ObjectTpe.decl(method.name) != NoSymbol && method.overrideChain.last.owner == ObjectClass
+
// whether to reference the type of the receiver or
// the type of the method owner
- val useMethodOwner = (
+ val useMethodOwner = ((
!style.isVirtual
|| hostSymbol.isBottomClass
|| methodOwner == definitions.ObjectClass
- )
+ ) && !(style.isSuper && hostSymbol != null)) || isTraitCallToObjectMethod
val receiver = if (useMethodOwner) methodOwner else hostSymbol
val jowner = internalName(receiver)
+
+ if (style.isSuper && (isTraitCallToObjectMethod || receiver.isTraitOrInterface) && !cnode.interfaces.contains(jowner))
+ cnode.interfaces.add(jowner)
+
val jname = method.javaSimpleName.toString
val bmType = methodBTypeFromSymbol(method)
val mdescr = bmType.descriptor
@@ -1342,7 +1365,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
def asmType(sym: Symbol) = classBTypeFromSymbol(sym).toASMType
val implMethodHandle =
- new asm.Handle(if (lambdaTarget.hasFlag(Flags.STATIC)) asm.Opcodes.H_INVOKESTATIC else asm.Opcodes.H_INVOKEVIRTUAL,
+ new asm.Handle(if (lambdaTarget.hasFlag(Flags.STATIC)) asm.Opcodes.H_INVOKESTATIC else if (lambdaTarget.owner.isTrait) asm.Opcodes.H_INVOKEINTERFACE else asm.Opcodes.H_INVOKEVIRTUAL,
classBTypeFromSymbol(lambdaTarget.owner).internalName,
lambdaTarget.name.toString,
methodBTypeFromSymbol(lambdaTarget).descriptor)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
index 2698225a06..324fc10eae 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
@@ -32,7 +32,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
* the InnerClass / EnclosingMethod classfile attributes. See comment in BTypes.
*/
def considerAsTopLevelImplementationArtifact(classSym: Symbol) =
- classSym.isImplClass || classSym.isSpecialized
+ classSym.isSpecialized
/**
* Cache the value of delambdafy == "inline" for each run. We need to query this value many
@@ -145,15 +145,12 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
assert(classSym.isClass, classSym)
def doesNotExist(method: Symbol) = {
- // (1) SI-9124, some trait methods don't exist in the generated interface. see comment in BTypes.
- // (2) Value classes. Member methods of value classes exist in the generated box class. However,
+ // Value classes. Member methods of value classes exist in the generated box class. However,
// nested methods lifted into a value class are moved to the companion object and don't exist
// in the value class itself. We can identify such nested methods: the initial enclosing class
// is a value class, but the current owner is some other class (the module class).
- method.owner.isTrait && method.isImplOnly || { // (1)
- val enclCls = nextEnclosingClass(method)
- exitingPickler(enclCls.isDerivedValueClass) && method.owner != enclCls // (2)
- }
+ val enclCls = nextEnclosingClass(method)
+ exitingPickler(enclCls.isDerivedValueClass) && method.owner != enclCls
}
def enclosingMethod(sym: Symbol): Option[Symbol] = {
@@ -248,7 +245,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
* Build the [[InlineInfo]] for a class symbol.
*/
def buildInlineInfoFromClassSymbol(classSym: Symbol, classSymToInternalName: Symbol => InternalName, methodSymToDescriptor: Symbol => String): InlineInfo = {
- val traitSelfType = if (classSym.isTrait && !classSym.isImplClass) {
+ val traitSelfType = if (classSym.isTrait) {
// The mixin phase uses typeOfThis for the self parameter in implementation class methods.
val selfSym = classSym.typeOfThis.typeSymbol
if (selfSym != classSym) Some(classSymToInternalName(selfSym)) else None
@@ -259,7 +256,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
val isEffectivelyFinal = classSym.isEffectivelyFinal
val sam = {
- if (classSym.isImplClass || classSym.isEffectivelyFinal) None
+ if (classSym.isEffectivelyFinal) None
else {
// Phase travel necessary. For example, nullary methods (getter of an abstract val) get an
// empty parameter list in later phases and would therefore be picked as SAM.
@@ -284,41 +281,15 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
val name = methodSym.javaSimpleName.toString // same as in genDefDef
val signature = name + methodSymToDescriptor(methodSym)
- // Some detours are required here because of changing flags (lateDEFERRED, lateMODULE):
+ // Some detours are required here because of changing flags (lateDEFERRED):
// 1. Why the phase travel? Concrete trait methods obtain the lateDEFERRED flag in Mixin.
// This makes isEffectivelyFinalOrNotOverridden false, which would prevent non-final
// but non-overridden methods of sealed traits from being inlined.
- // 2. Why the special case for `classSym.isImplClass`? Impl class symbols obtain the
- // lateMODULE flag during Mixin. During the phase travel to exitingPickler, the late
- // flag is ignored. The members are therefore not isEffectivelyFinal (their owner
- // is not a module). Since we know that all impl class members are static, we can
- // just take the shortcut.
- val effectivelyFinal = classSym.isImplClass || exitingPickler(methodSym.isEffectivelyFinalOrNotOverridden)
-
- // Identify trait interface methods that have a static implementation in the implementation
- // class. Invocations of these methods can be re-wrired directly to the static implementation
- // if they are final or the receiver is known.
- //
- // Using `erasure.needsImplMethod` is not enough: it keeps field accessors, module getters
- // and super accessors. When AddInterfaces creates the impl class, these methods are
- // initially added to it.
- //
- // The mixin phase later on filters out most of these members from the impl class (see
- // Mixin.isImplementedStatically). However, accessors for concrete lazy vals remain in the
- // impl class after mixin. So the filter in mixin is not exactly what we need here (we
- // want to identify concrete trait methods, not any accessors). So we check some symbol
- // properties manually.
- val traitMethodWithStaticImplementation = {
- import symtab.Flags._
- classSym.isTrait && !classSym.isImplClass &&
- erasure.needsImplMethod(methodSym) &&
- !methodSym.isModule &&
- !(methodSym hasFlag (ACCESSOR | SUPERACCESSOR))
- }
+ val effectivelyFinal = exitingPickler(methodSym.isEffectivelyFinalOrNotOverridden) && !(methodSym.owner.isTrait && methodSym.isModule)
val info = MethodInlineInfo(
effectivelyFinal = effectivelyFinal,
- traitMethodWithStaticImplementation = traitMethodWithStaticImplementation,
+ traitMethodWithStaticImplementation = false,
annotatedInline = methodSym.hasAnnotation(ScalaInlineClass),
annotatedNoInline = methodSym.hasAnnotation(ScalaNoInlineClass)
)
@@ -866,7 +837,6 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
|| sym.isArtifact
|| sym.isLiftedMethod
|| sym.isBridge
- || (sym.ownerChain exists (_.isImplClass))
)
/* @return
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
index 96796b3244..20b1a52818 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
@@ -174,7 +174,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
if (lmoc != NoSymbol) {
// it must be a top level class (name contains no $s)
val isCandidateForForwarders = {
- exitingPickler { !(lmoc.name.toString contains '$') && lmoc.hasModuleFlag && !lmoc.isImplClass && !lmoc.isNestedClass }
+ exitingPickler { !(lmoc.name.toString contains '$') && lmoc.hasModuleFlag && !lmoc.isNestedClass }
}
if (isCandidateForForwarders) {
log(s"Adding static forwarders from '$claszSymbol' to implementations in '$lmoc'")
@@ -563,7 +563,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
}
val isNative = methSymbol.hasAnnotation(definitions.NativeAttr)
- val isAbstractMethod = (methSymbol.isDeferred || methSymbol.owner.isInterface) && !methSymbol.hasFlag(Flags.JAVA_DEFAULTMETHOD)
+ val isAbstractMethod = rhs == EmptyTree
val flags = GenBCode.mkFlags(
javaFlags(methSymbol),
if (isAbstractMethod) asm.Opcodes.ACC_ABSTRACT else 0,
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
index 3c2ee89b05..85563be428 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
@@ -172,7 +172,6 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
*/
def primitiveOrClassToBType(sym: Symbol): BType = {
assertClassNotArray(sym)
- assert(!sym.isImplClass, sym)
primitiveTypeToBType.getOrElse(sym, classBTypeFromSymbol(sym))
}
@@ -337,7 +336,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
// Check for hasAnnotationFlag for SI-9393: the classfile / java source parsers add
// scala.annotation.Annotation as superclass to java annotations. In reality, java
// annotation classfiles have superclass Object (like any interface classfile).
- val superClassSym = if (classSym.isImplClass || classSym.hasJavaAnnotationFlag) ObjectClass else {
+ val superClassSym = if (classSym.hasJavaAnnotationFlag) ObjectClass else {
val sc = classSym.superClass
// SI-9393: Java annotation classes don't have the ABSTRACT/INTERFACE flag, so they appear
// (wrongly) as superclasses. Fix this for BTypes: the java annotation will appear as interface
@@ -603,11 +602,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
*/
final def isTopLevelModuleClass(sym: Symbol): Boolean = exitingPickler {
// phase travel to pickler required for isNestedClass (looks at owner)
- val r = sym.isModuleClass && !sym.isNestedClass
- // The mixin phase adds the `lateMODULE` flag to trait implementation classes. Since the flag
- // is late, it should not be visible here inside the time travel. We check this.
- if (r) assert(!sym.isImplClass, s"isModuleClass should be false for impl class $sym")
- r
+ sym.isModuleClass && !sym.isNestedClass
}
/**
@@ -684,7 +679,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
val finalFlag = (
(((sym.rawflags & symtab.Flags.FINAL) != 0) || isTopLevelModuleClass(sym))
- && !sym.enclClass.isInterface
+ && !sym.enclClass.isTrait
&& !sym.isClassConstructor
&& !sym.isMutable // lazy vals and vars both
)
@@ -697,12 +692,12 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
GenBCode.mkFlags(
if (privateFlag) ACC_PRIVATE else ACC_PUBLIC,
if ((sym.isDeferred && !sym.hasFlag(symtab.Flags.JAVA_DEFAULTMETHOD))|| sym.hasAbstractFlag) ACC_ABSTRACT else 0,
- if (sym.isInterface) ACC_INTERFACE else 0,
+ if (sym.isTraitOrInterface) ACC_INTERFACE else 0,
if (finalFlag && !sym.hasAbstractFlag) ACC_FINAL else 0,
if (sym.isStaticMember) ACC_STATIC else 0,
if (sym.isBridge) ACC_BRIDGE | ACC_SYNTHETIC else 0,
if (sym.isArtifact) ACC_SYNTHETIC else 0,
- if (sym.isClass && !sym.isInterface) ACC_SUPER else 0,
+ if (sym.isClass && !sym.isTraitOrInterface) ACC_SUPER else 0,
if (sym.hasJavaEnumFlag) ACC_ENUM else 0,
if (sym.isVarargsMethod) ACC_VARARGS else 0,
if (sym.hasFlag(symtab.Flags.SYNCHRONIZED)) ACC_SYNCHRONIZED else 0,
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
index 17255cb880..6dd74bad84 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
@@ -137,7 +137,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
callee = method,
calleeDeclarationClass = declarationClassBType,
safeToInline = safeToInline,
- safeToRewrite = safeToRewrite,
+ safeToRewrite = false,
canInlineFromSource = canInlineFromSource,
annotatedInline = annotatedInline,
annotatedNoInline = annotatedNoInline,
@@ -299,7 +299,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
receiverType.info.orThrow.inlineInfo.isEffectivelyFinal // (1)
}
- val isRewritableTraitCall = isStaticallyResolved && methodInlineInfo.traitMethodWithStaticImplementation
+ val isRewritableTraitCall = false
val warning = calleeDeclarationClassBType.info.orThrow.inlineInfo.warning.map(
MethodInlineInfoIncomplete(calleeDeclarationClassBType.internalName, calleeMethodNode.name, calleeMethodNode.desc, _))
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
index 9847c9db58..32106614e3 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
@@ -27,7 +27,7 @@ class Inliner[BT <: BTypes](val btypes: BT) {
import backendUtils._
def runInliner(): Unit = {
- rewriteFinalTraitMethodInvocations()
+// rewriteFinalTraitMethodInvocations()
for (request <- collectAndOrderInlineRequests) {
val Right(callee) = request.callsite.callee // collectAndOrderInlineRequests returns callsites with a known callee
diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
index 085a814c6b..1cee76ae65 100644
--- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
+++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala
@@ -14,202 +14,12 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
import global._ // the global environment
import definitions._ // standard classes and methods
- /** The phase sets lateINTERFACE for non-interface traits that now
- * become interfaces. It sets lateDEFERRED for formerly concrete
- * methods in such traits.
+ /** lateDEFERRED for formerly concrete methods in such traits.
*/
- override def phaseNewFlags: Long = lateDEFERRED | lateINTERFACE
-
- /** A lazily constructed map that associates every non-interface trait with
- * its implementation class.
- */
- private val implClassMap = perRunCaches.newMap[Symbol, Symbol]()
-
- /** A lazily constructed map that associates every concrete method in a non-interface
- * trait that's currently compiled with its corresponding method in the trait's
- * implementation class.
- */
- private val implMethodMap = perRunCaches.newMap[Symbol, Symbol]()
-
- override def newPhase(prev: scala.tools.nsc.Phase): StdPhase = {
- implClassMap.clear()
- implMethodMap.clear()
- super.newPhase(prev)
- }
-
- /** Is given trait member symbol a member of the trait's interface
- * after this transform is performed?
- */
- private def isInterfaceMember(sym: Symbol) = (
- sym.isType || {
- sym.info // initialize to set lateMETHOD flag if necessary
-
- ( sym.isMethod
- && !sym.isLabel
- && !sym.isPrivate
- && (!(sym hasFlag BRIDGE) || sym.hasBridgeAnnotation) // count @bridge annotated classes as interface members
- && !sym.isConstructor
- && !sym.isImplOnly
- )
- }
- )
-
- /** Does symbol need an implementation method? */
- def needsImplMethod(sym: Symbol) = (
- sym.isMethod
- && isInterfaceMember(sym)
- && (!sym.hasFlag(DEFERRED | SUPERACCESSOR) || (sym hasFlag lateDEFERRED))
- )
-
- def implClassPhase = currentRun.erasurePhase.next
-
- 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 impl0 = {
- if (!inClass) NoSymbol
- else {
- val typeInfo = iface.owner.info
- typeInfo.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.
- // TODO this is not taken into account by flat classpath yet
- classPath match {
- case cp: ClassPath[_] if !cp.context.isValidName(implName + ".class") =>
- log(s"not unlinking $iface's existing implClass ${implSym.name} because it is not on the classpath.")
- implSym
- case _ =>
- typeInfo.decls unlink implSym
- NoSymbol
- }
- }
- }
- }
-
- 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.associatedFile = 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 if one does not yet exist */
- def implClass(iface: Symbol): Symbol = {
- iface.info
-
- implClassMap.getOrElse(iface, enteringPhase(implClassPhase) {
- if (iface.implClass eq NoSymbol)
- debuglog(s"${iface.fullLocationString} has no implClass yet, creating it now.")
- else
- log(s"${iface.fullLocationString} impl class is ${iface.implClass.nameString}")
-
- newImplClass(iface)
- })
- }
-
- /** A lazy type to set the info of an implementation class
- * The parents of an implementation class for trait iface are:
- *
- * - superclass: Object
- * - mixin classes: mixin classes of iface where every non-interface
- * trait is mapped to its implementation class, followed by iface itself.
- *
- * The declarations of a mixin class are:
- * - for every interface member of iface: its implementation method, if one is needed
- * - every former member of iface that is implementation only
- */
- private class LazyImplClassType(iface: Symbol) extends LazyType with FlagAgnosticCompleter {
- /** Compute the decls of implementation class implClass,
- * given the decls ifaceDecls of its interface.
- */
- private def implDecls(implClass: Symbol, ifaceDecls: Scope): Scope = {
- debuglog("LazyImplClassType calculating decls for " + implClass)
-
- val decls = newScope
- 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, UnitTpe)
- )
- }
-
- for (sym <- ifaceDecls) {
- if (isInterfaceMember(sym)) {
- if (needsImplMethod(sym)) {
- val clone = sym.cloneSymbol(implClass).resetFlag(lateDEFERRED)
- if (currentRun.compiles(implClass)) implMethodMap(sym) = clone
- decls enter clone
- sym setFlag lateDEFERRED
- if (!sym.isSpecialized)
- log(s"Cloned ${sym.name} from ${sym.owner} into implClass ${implClass.fullName}")
- }
- }
- else {
- log(s"Destructively modifying owner of $sym from ${sym.owner} to $implClass")
- sym.owner = implClass
- // note: OK to destructively modify the owner here,
- // because symbol will not be accessible from outside the sourcefile.
- // mixin constructors are corrected separately; see TermSymbol.owner
- decls enter sym
- }
- }
-
- decls
- }
-
- override def complete(implSym: Symbol) {
- debuglog("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 = 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)
- case _ =>
- tp
- }
- }
- def implType(tp: Type): Type = tp match {
- case ClassInfoType(parents, decls, _) =>
- assert(phase == implClassPhase, tp)
- // Impl class parents: Object first, matching interface last.
- val implParents = ObjectTpe +: (parents.tail map mixinToImplClass filter (_.typeSymbol != ObjectClass)) :+ iface.tpe
- ClassInfoType(implParents, implDecls(implSym, decls), implSym)
- case PolyType(_, restpe) =>
- implType(restpe)
- }
- implSym setInfo implType(enteringErasure(iface.info))
- }
-
- override def load(clazz: Symbol) { complete(clazz) }
- }
+ override def phaseNewFlags: Long = lateDEFERRED
def transformMixinInfo(tp: Type): Type = tp match {
case ClassInfoType(parents, decls, clazz) if clazz.isPackageClass || !clazz.isJavaDefined =>
- if (clazz.needsImplClass)
- implClass(clazz setFlag lateINTERFACE) // generate an impl class
val parents1 = parents match {
case Nil => Nil
@@ -218,21 +28,20 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
if (clazz.isTrait) ObjectTpe :: tl
else parents
}
- val decls1 = scopeTransform(clazz)(
- decls filter (sym =>
- if (clazz.isInterface) isInterfaceMember(sym)
- else sym.isClass || sym.isTerm
- )
- )
- ClassInfoType(parents1, decls1, clazz)
+ if (clazz.isTrait) {
+ decls foreach { sym =>
+ if (!sym.isType) sym.info // initialize to set lateMETHOD flag if necessary
+ }
+ }
+ if (parents1 eq parents) tp
+ else ClassInfoType(parents1, decls, clazz)
case _ =>
tp
}
// Tree transformation --------------------------------------------------------------
-
private class ChangeOwnerAndReturnTraverser(oldowner: Symbol, newowner: Symbol)
- extends ChangeOwnerTraverser(oldowner, newowner) {
+ extends ChangeOwnerTraverser(oldowner, newowner) {
override def traverse(tree: Tree) {
tree match {
case _: Return => change(tree.symbol)
@@ -242,61 +51,10 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
}
}
- private def isInterfaceTree(tree: Tree) = tree.isDef && isInterfaceMember(tree.symbol)
-
- private def deriveMemberForImplClass(tree: Tree): Tree =
- if (isInterfaceTree(tree)) if (needsImplMethod(tree.symbol)) implMethodDef(tree) else EmptyTree
- else tree
-
- private def deriveMemberForInterface(tree: Tree): Tree =
- if (isInterfaceTree(tree)) if (needsImplMethod(tree.symbol)) DefDef(tree.symbol, EmptyTree) else tree
- else EmptyTree
-
- private def ifaceTemplate(templ: Template): Template =
- treeCopy.Template(templ, templ.parents, noSelfType, templ.body map deriveMemberForInterface)
-
- /** Transforms the member tree containing the implementation
- * into a member of the impl class.
- */
- private def implMethodDef(tree: Tree): Tree = {
- val impl = implMethodMap.getOrElse(tree.symbol, abort("implMethod missing for " + tree.symbol))
-
- val newTree = if (impl.isErroneous) tree else { // e.g. res/t687
- // SI-5167: Ensure that the tree that we are grafting refers the parameter symbols from the
- // new method symbol `impl`, rather than the symbols of the original method signature in
- // the trait. `tree setSymbol impl` does *not* suffice!
- val DefDef(_, _, _, vparamss, _, _) = tree
- val oldSyms = vparamss.flatten.map(_.symbol)
- val newSyms = impl.info.paramss.flatten
- assert(oldSyms.length == newSyms.length, (oldSyms, impl, impl.info))
- tree.substituteSymbols(oldSyms, newSyms)
- }
- new ChangeOwnerAndReturnTraverser(newTree.symbol, impl)(newTree setSymbol impl)
- }
-
- /** Add mixin constructor definition
- * def $init$(): Unit = ()
- * to `stats` unless there is already one.
- */
- private def addMixinConstructorDef(clazz: Symbol, stats: List[Tree]): List[Tree] =
- if (treeInfo.firstConstructor(stats) != EmptyTree) stats
- else DefDef(clazz.primaryConstructor, Block(List(), Literal(Constant(())))) :: stats
-
- private def implTemplate(clazz: Symbol, templ: Template): Template = atPos(templ.pos) {
- val templ1 = (
- Template(templ.parents, noSelfType, addMixinConstructorDef(clazz, templ.body map deriveMemberForImplClass))
- setSymbol clazz.newLocalDummy(templ.pos)
- )
- templ1.changeOwner(templ.symbol.owner -> clazz, templ.symbol -> templ1.symbol)
- templ1
- }
-
- def implClassDefs(trees: List[Tree]): List[Tree] = {
- trees collect {
- case cd: ClassDef if cd.symbol.needsImplClass =>
- val clazz = implClass(cd.symbol).initialize
- ClassDef(clazz, implTemplate(clazz, cd.impl))
- }
+ private def mkAssign(clazz: Symbol, assignSym: Symbol, rhs: Tree): Tree = {
+ val qual = Select(This(clazz), assignSym)
+ if (assignSym.isSetter) Apply(qual, List(rhs))
+ else Assign(qual, rhs)
}
/** Add calls to supermixin constructors
@@ -304,15 +62,16 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
* to tree, which is assumed to be the body of a constructor of class clazz.
*/
private def addMixinConstructorCalls(tree: Tree, clazz: Symbol): Tree = {
- def mixinConstructorCall(impl: Symbol): Tree = atPos(tree.pos) {
- Apply(Select(This(clazz), impl.primaryConstructor), List())
+ def mixinConstructorCall(mc: Symbol): Tree = atPos(tree.pos) {
+ Apply(SuperSelect(clazz, mc.primaryConstructor), Nil)
}
val mixinConstructorCalls: List[Tree] = {
for (mc <- clazz.mixinClasses.reverse
- if mc.hasFlag(lateINTERFACE))
- yield mixinConstructorCall(implClass(mc))
+ if mc.isTrait && mc.primaryConstructor != NoSymbol)
+ yield mixinConstructorCall(mc)
}
tree match {
+
case Block(Nil, expr) =>
// AnyVal constructor - have to provide a real body so the
// jvm doesn't throw a VerifyError. But we can't add the
@@ -329,42 +88,14 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
}
protected val mixinTransformer = new Transformer {
- override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] =
- (super.transformStats(stats, exprOwner) :::
- super.transformStats(implClassDefs(stats), exprOwner))
override def transform(tree: Tree): Tree = {
val sym = tree.symbol
val tree1 = tree match {
- case ClassDef(mods, _, _, impl) if sym.needsImplClass =>
- implClass(sym).initialize // to force lateDEFERRED flags
- copyClassDef(tree)(mods = mods | INTERFACE, impl = ifaceTemplate(impl))
case DefDef(_,_,_,_,_,_) if sym.isClassConstructor && sym.isPrimaryConstructor && sym.owner != ArrayClass =>
deriveDefDef(tree)(addMixinConstructorCalls(_, sym.owner)) // (3)
case Template(parents, self, body) =>
val parents1 = sym.owner.info.parents map (t => TypeTree(t) setPos tree.pos)
treeCopy.Template(tree, parents1, noSelfType, body)
- case This(_) if sym.needsImplClass =>
- val impl = implClass(sym)
- var owner = currentOwner
- while (owner != sym && owner != impl) owner = owner.owner;
- if (owner == impl) This(impl) setPos tree.pos
- else tree
- //TODO what about this commented out code?
-/* !!!
- case Super(qual, mix) =>
- val mix1 = mix
- if (mix == tpnme.EMPTY) mix
- else {
- val ps = enteringErasure {
- sym.info.parents dropWhile (p => p.symbol.name != mix)
- }
- assert(!ps.isEmpty, tree);
- if (ps.head.symbol.needsImplClass) implClass(ps.head.symbol).name
- else mix
- }
- if (sym.needsImplClass) Super(implClass(sym), mix1) setPos tree.pos
- else treeCopy.Super(tree, qual, mix1)
-*/
case _ =>
tree
}
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index ea14c96725..1e479d3f63 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -73,7 +73,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
override def transform(tree: Tree): Tree = {
tree match {
- case cd @ ClassDef(mods0, name0, tparams0, impl0) if !cd.symbol.isInterface && !isPrimitiveValueClass(cd.symbol) =>
+ case cd @ ClassDef(mods0, name0, tparams0, impl0) if !isPrimitiveValueClass(cd.symbol) && cd.symbol.primaryConstructor != NoSymbol =>
if(cd.symbol eq AnyValClass) {
cd
}
@@ -456,7 +456,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
// find and dissect primary constructor
private val (primaryConstr, _primaryConstrParams, primaryConstrBody) = stats collectFirst {
- case dd@DefDef(_, _, _, vps :: Nil, _, rhs: Block) if dd.symbol.isPrimaryConstructor => (dd, vps map (_.symbol), rhs)
+ case dd@DefDef(_, _, _, vps :: Nil, _, rhs: Block) if dd.symbol.isPrimaryConstructor || dd.symbol.isMixinConstructor => (dd, vps map (_.symbol), rhs)
} getOrElse {
abort("no constructor in template: impl = " + impl)
}
@@ -517,9 +517,11 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
case Apply(Select(This(_), _), List()) =>
// references to parameter accessor methods of own class become references to parameters
// outer accessors become references to $outer parameter
- if (canBeSupplanted(tree.symbol))
+ if (clazz.isTrait)
+ super.transform(tree)
+ else if (canBeSupplanted(tree.symbol))
gen.mkAttributedIdent(parameter(tree.symbol.accessed)) setPos tree.pos
- else if (tree.symbol.outerSource == clazz && !clazz.isImplClass)
+ else if (tree.symbol.outerSource == clazz)
gen.mkAttributedIdent(parameterNamed(nme.OUTER)) setPos tree.pos
else
super.transform(tree)
@@ -566,7 +568,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
}
// Constant typed vals are not memoized.
- def memoizeValue(sym: Symbol) = !sym.info.isInstanceOf[ConstantType]
+ def memoizeValue(sym: Symbol) = !sym.info.resultType.isInstanceOf[ConstantType]
/** Triage definitions and statements in this template into the following categories.
* The primary constructor is treated separately, as it is assembled in part from these pieces.
@@ -587,7 +589,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
for (stat <- primaryConstrBody.stats) {
constrStatBuf += stat
stat match {
- case ValDef(mods, name, _, _) if mods hasFlag PRESUPER =>
+ case ValDef(mods, name, _, _) if mods.hasFlag(PRESUPER) =>
// stat is the constructor-local definition of the field value
val fields = presupers filter (_.getterName == name)
assert(fields.length == 1, s"expected exactly one field by name $name in $presupers of $clazz's early initializers")
@@ -624,12 +626,12 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
stat match {
// recurse on class definition, store in defBuf
- case _: ClassDef => defBuf += new ConstructorTransformer(unit).transform(stat)
+ case _: ClassDef if !stat.symbol.isInterface => defBuf += new ConstructorTransformer(unit).transform(stat)
// Triage methods -- they all end up in the template --
// regular ones go to `defBuf`, secondary contructors go to `auxConstructorBuf`.
// The primary constructor is dealt with separately (we're massaging it here).
- case _: DefDef if statSym.isPrimaryConstructor => ()
+ case _: DefDef if statSym.isPrimaryConstructor || statSym.isMixinConstructor => ()
case _: DefDef if statSym.isConstructor => auxConstructorBuf += stat
case _: DefDef => defBuf += stat
diff --git a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
index b74292fa65..67e3f67f2f 100644
--- a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
+++ b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
@@ -260,7 +260,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
val body =
Block(
List(
- Apply(Select(Super(gen.mkAttributedThis(newClass), tpnme.EMPTY) setPos newClass.pos, nme.CONSTRUCTOR) setPos newClass.pos, Nil) setPos newClass.pos
+ atPos(newClass.pos)(Apply(gen.mkSuperInitCall, Nil))
) ++ assigns,
Literal(Constant(())): Tree
) setPos newClass.pos
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 0e44751a3f..41f22e5669 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -662,7 +662,7 @@ abstract class Erasure extends AddInterfaces
adaptMember(selectFrom(applied))
} else if (!(qual1.isInstanceOf[Super] || (qual1.tpe.typeSymbol isSubClass tree.symbol.owner))) {
assert(tree.symbol.owner != ArrayClass)
- selectFrom(cast(qual1, tree.symbol.owner.tpe))
+ selectFrom(cast(qual1, tree.symbol.owner.tpe.resultType))
} else {
selectFrom(qual1)
}
@@ -1103,7 +1103,6 @@ abstract class Erasure extends AddInterfaces
}
} else tree
case Template(parents, self, body) =>
- assert(!currentOwner.isImplClass)
//Console.println("checking no dble defs " + tree)//DEBUG
checkNoDoubleDefs(tree.symbol.owner)
treeCopy.Template(tree, parents, noSelfType, addBridges(body, currentOwner))
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index 4abcc774da..3d6fad4238 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -210,7 +210,7 @@ abstract class ExplicitOuter extends InfoTransform
// class needs to have a common naming scheme, independently of whether
// the field was accessed from an inner class or not. See #2946
if (sym.owner.isTrait && sym.isLocalToThis &&
- (sym.getterIn(sym.owner.toInterface) == NoSymbol))
+ (sym.getterIn(sym.owner) == NoSymbol))
sym.makeNotPrivate(sym.owner)
tp
}
@@ -241,12 +241,17 @@ abstract class ExplicitOuter extends InfoTransform
* Will return `EmptyTree` if there is no outer accessor because of a premature self reference.
*/
private def outerSelect(base: Tree): Tree = {
- val baseSym = base.tpe.typeSymbol.toInterface
+ val baseSym = base.tpe.typeSymbol
val outerAcc = outerAccessor(baseSym)
- if (outerAcc == NoSymbol && baseSym.ownersIterator.exists(isUnderConstruction)) {
- // e.g neg/t6666.scala
- // The caller will report the error with more information.
- EmptyTree
+ if (outerAcc == NoSymbol) {
+ if (baseSym.ownersIterator.exists(isUnderConstruction)) {
+ // e.g neg/t6666.scala
+ // The caller will report the error with more information.
+ EmptyTree
+ } else {
+ globalError(currentOwner.pos, s"Internal error: unable to find the outer accessor symbol of $baseSym")
+ EmptyTree
+ }
} else {
val currentClass = this.currentClass //todo: !!! if this line is removed, we get a build failure that protected$currentClass need an override modifier
// outerFld is the $outer field of the current class, if the reference can
@@ -254,6 +259,7 @@ abstract class ExplicitOuter extends InfoTransform
// otherwise it is NoSymbol
val outerFld =
if (outerAcc.owner == currentClass &&
+ !outerAcc.owner.isTrait &&
base.tpe =:= currentClass.thisType &&
outerAcc.owner.isEffectivelyFinal)
outerField(currentClass) suchThat (_.owner == currentClass)
@@ -274,8 +280,7 @@ abstract class ExplicitOuter extends InfoTransform
*/
protected def outerPath(base: Tree, from: Symbol, to: Symbol): Tree = {
//Console.println("outerPath from "+from+" to "+to+" at "+base+":"+base.tpe)
- //assert(base.tpe.widen.baseType(from.toInterface) != NoType, ""+base.tpe.widen+" "+from.toInterface)//DEBUG
- if (from == to || from.isImplClass && from.toInterface == to) base
+ if (from == to) base
else outerPath(outerSelect(base), from.outerClass, to)
}
@@ -400,7 +405,7 @@ abstract class ExplicitOuter extends InfoTransform
case Template(parents, self, decls) =>
val newDefs = new ListBuffer[Tree]
atOwner(tree, currentOwner) {
- if (!currentClass.isInterface || (currentClass hasFlag lateINTERFACE)) {
+ if (!currentClass.isInterface) {
if (isInner(currentClass)) {
if (hasOuterField(currentClass))
newDefs += outerFieldDef // (1a)
@@ -479,7 +484,7 @@ abstract class ExplicitOuter extends InfoTransform
// base.<outer>.eq(o) --> base.$outer().eq(o) if there's an accessor, else the whole tree becomes TRUE
// TODO remove the synthetic `<outer>` method from outerFor??
case Apply(eqsel@Select(eqapp@Apply(sel@Select(base, nme.OUTER_SYNTH), Nil), eq), args) =>
- val outerFor = sel.symbol.owner.toInterface // TODO: toInterface necessary?
+ val outerFor = sel.symbol.owner
val acc = outerAccessor(outerFor)
if (acc == NoSymbol ||
diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala
index fbb0307773..0db9f19597 100644
--- a/src/compiler/scala/tools/nsc/transform/Flatten.scala
+++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala
@@ -41,8 +41,6 @@ abstract class Flatten extends InfoTransform {
}
private def liftSymbol(sym: Symbol) {
liftClass(sym)
- if (sym.needsImplClass)
- liftClass(erasure implClass sym)
}
// This is a short-term measure partially working around objects being
// lifted out of parameterized classes, leaving them referencing
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index a372136781..7a5bd747c4 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -98,11 +98,6 @@ abstract class LambdaLift extends InfoTransform {
*/
private val proxyNames = mutable.HashMap[Symbol, Name]()
- // (trait, name) -> owner
- private val localTraits = mutable.HashMap[(Symbol, Name), Symbol]()
- // (owner, name) -> implClass
- private val localImplClasses = mutable.HashMap[(Symbol, Name), Symbol]()
-
/** A flag to indicate whether new free variables have been found */
private var changedFreeVars: Boolean = _
@@ -176,24 +171,7 @@ abstract class LambdaLift extends InfoTransform {
case ClassDef(_, _, _, _) =>
liftedDefs(tree.symbol) = Nil
if (sym.isLocalToBlock) {
- // Don't rename implementation classes independently of their interfaces. If
- // the interface is to be renamed, then we will rename the implementation
- // class at that time. You'd think we could call ".implClass" on the trait
- // rather than collecting them in another map, but that seems to fail for
- // exactly the traits being renamed here (i.e. defined in methods.)
- //
- // !!! - it makes no sense to have methods like "implClass" and
- // "companionClass" which fail for an arbitrary subset of nesting
- // arrangements, and then have separate methods which attempt to compensate
- // for that failure. There should be exactly one method for any given
- // entity which always gives the right answer.
- if (sym.isImplClass)
- localImplClasses((sym.owner, tpnme.interfaceName(sym.name))) = sym
- else {
- renamable += sym
- if (sym.isTrait)
- localTraits((sym, sym.name)) = sym.owner
- }
+ renamable += sym
}
case DefDef(_, _, _, _, _, _) =>
if (sym.isLocalToBlock) {
@@ -264,40 +242,18 @@ abstract class LambdaLift extends InfoTransform {
// Generating a unique name, mangled with the enclosing full class name (including
// package - subclass might have the same name), avoids a VerifyError in the case
// that a sub-class happens to lifts out a method with the *same* name.
- if (originalName.isTermName && !sym.enclClass.isImplClass && calledFromInner(sym))
+ if (originalName.isTermName && calledFromInner(sym))
newTermNameCached(nonAnon(sym.enclClass.fullName('$')) + nme.EXPAND_SEPARATOR_STRING + name)
else
name
}
}
- /* Rename a trait's interface and implementation class in coordinated fashion. */
- def renameTrait(traitSym: Symbol, implSym: Symbol) {
- val originalImplName = implSym.name
- renameSym(traitSym)
- implSym setName tpnme.implClassName(traitSym.name)
-
- debuglog("renaming impl class in step with %s: %s => %s".format(traitSym, originalImplName, implSym.name))
- }
-
val allFree: Set[Symbol] = free.values.flatMap(_.iterator).toSet
for (sym <- renamable) {
- // If we renamed a trait from Foo to Foo$1, we must rename the implementation
- // class from Foo$class to Foo$1$class. (Without special consideration it would
- // become Foo$class$1 instead.) Since the symbols are being renamed out from
- // under us, and there's no reliable link between trait symbol and impl symbol,
- // we have maps from ((trait, name)) -> owner and ((owner, name)) -> impl.
- localTraits remove ((sym, sym.name)) match {
- case None =>
- if (allFree(sym)) proxyNames(sym) = newName(sym)
- else renameSym(sym)
- case Some(owner) =>
- localImplClasses remove ((owner, sym.name)) match {
- case Some(implSym) => renameTrait(sym, implSym)
- case _ => renameSym(sym) // pure interface, no impl class
- }
- }
+ if (allFree(sym)) proxyNames(sym) = newName(sym)
+ else renameSym(sym)
}
afterOwnPhase {
@@ -456,7 +412,6 @@ abstract class LambdaLift extends InfoTransform {
}
sym.owner = sym.owner.enclClass
- if (sym.isClass) sym.owner = sym.owner.toInterface
if (sym.isMethod) sym setFlag LIFTED
liftedDefs(sym.owner) ::= tree
// TODO: this modifies the ClassInfotype of the enclosing class, which is associated with another phase (explicitouter).
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index d13e11e9ec..ed7ef0d8fd 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -32,8 +32,9 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
// --------- helper functions -----------------------------------------------
/** A member of a trait is implemented statically if its implementation after the
- * mixin transform is in the static implementation module. To be statically
- * implemented, a member must be a method that belonged to the trait's implementation class
+ * mixin transform is RHS of the method body (destined to be in a interface default method)
+ *
+ * To be statically implemented, a member must be a method that belonged to the trait's implementation class
* before (i.e. it is not abstract). Not statically implemented are
* - non-private modules: these are implemented directly in the mixin composition class
* (private modules, on the other hand, are implemented statically, but their
@@ -43,33 +44,18 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* methods in the impl class (because they can have arbitrary initializers)
*/
private def isImplementedStatically(sym: Symbol) = (
- sym.owner.isImplClass
+ sym.isMethod
+ && (!sym.hasFlag(DEFERRED | SUPERACCESSOR) || (sym hasFlag lateDEFERRED))
+ && sym.owner.isTrait
&& sym.isMethod
&& (!sym.isModule || sym.hasFlag(PRIVATE | LIFTED))
&& (!(sym hasFlag (ACCESSOR | SUPERACCESSOR)) || sym.isLazy)
+ && !sym.isPrivate
+ && !sym.hasAllFlags(LIFTED | MODULE | METHOD)
+ && !sym.isConstructor
+ && (!sym.hasFlag(notPRIVATE | LIFTED) || sym.hasFlag(ACCESSOR | SUPERACCESSOR | MODULE))
)
- /** A member of a trait is static only if it belongs only to the
- * implementation class, not the interface, and it is implemented
- * statically.
- */
- private def isStaticOnly(sym: Symbol) =
- isImplementedStatically(sym) && sym.isImplOnly
-
- /** A member of a trait is forwarded if it is implemented statically and it
- * is also visible in the trait's interface. In that case, a forwarder to
- * the member's static implementation will be added to the class that
- * inherits the trait.
- */
- private def isForwarded(sym: Symbol) =
- isImplementedStatically(sym) && !sym.isImplOnly
-
- /** Maps the type of an implementation class to its interface;
- * maps all other types to themselves.
- */
- private def toInterface(tp: Type): Type =
- enteringMixin(tp.typeSymbol.toInterface).tpe
-
private def isFieldWithBitmap(field: Symbol) = {
field.info // ensure that nested objects are transformed
// For checkinit consider normal value getters
@@ -97,22 +83,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
&& !(sym.accessed hasAnnotation TransientAttr)
)
- /** Maps all parts of this type that refer to implementation classes to
- * their corresponding interfaces.
- */
- private val toInterfaceMap = new TypeMap {
- def apply(tp: Type): Type = mapOver( tp match {
- case TypeRef(pre, sym, args) if sym.isImplClass =>
- typeRef(pre, enteringMixin(sym.toInterface), args)
- case _ => tp
- })
- }
-
- /** The implementation class corresponding to a currently compiled interface.
- * todo: try to use Symbol.implClass instead?
- */
- private def implClass(iface: Symbol) = iface.implClass orElse (erasure implClass iface)
-
/** Returns the symbol that is accessed by a super-accessor in a mixin composition.
*
* @param base The class in which everything is mixed together
@@ -159,8 +129,8 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
/** Add given member to given class, and mark member as mixed-in.
*/
def addMember(clazz: Symbol, member: Symbol): Symbol = {
- debuglog("new member of " + clazz + ":" + member.defString)
- clazz.info.decls enter member setFlag MIXEDIN
+ debuglog(s"mixing into $clazz: ${member.defString}")
+ clazz.info.decls enter member setFlag MIXEDIN resetFlag JAVA_DEFAULTMETHOD
}
def cloneAndAddMember(mixinClass: Symbol, mixinMember: Symbol, clazz: Symbol): Symbol =
addMember(clazz, cloneBeforeErasure(mixinClass, mixinMember, clazz))
@@ -227,12 +197,11 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
}
clazz.info // make sure info is up to date, so that implClass is set.
- val impl = implClass(clazz) orElse abort("No impl class for " + clazz)
- for (member <- impl.info.decls) {
+ for (member <- clazz.info.decls) {
if (!member.isMethod && !member.isModule && !member.isModuleVar) {
assert(member.isTerm && !member.isDeferred, member)
- if (member.getterIn(impl).isPrivate) {
+ if (member.getterIn(clazz).isPrivate) {
member.makeNotPrivate(clazz) // this will also make getter&setter not private
}
val getter = member.getterIn(clazz)
@@ -241,6 +210,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
val setter = member.setterIn(clazz)
if (setter == NoSymbol) addMember(clazz, newSetter(member))
}
+ clazz.info.decls.unlink(member)
}
}
debuglog("new defs of " + clazz + " = " + clazz.info.decls)
@@ -266,16 +236,12 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
)
/* Mix in members of implementation class mixinClass into class clazz */
- def mixinImplClassMembers(mixinClass: Symbol, mixinInterface: Symbol) {
- if (!mixinClass.isImplClass) devWarning ("Impl class flag is not set " +
- ((mixinClass.debugLocationString, mixinInterface.debugLocationString)))
-
- for (member <- mixinClass.info.decls ; if isForwarded(member)) {
- val imember = member overriddenSymbol mixinInterface
- imember overridingSymbol clazz match {
+ def mixinTraitForwarders(mixinClass: Symbol) {
+ for (member <- mixinClass.info.decls ; if isImplementedStatically(member)) {
+ member overridingSymbol clazz match {
case NoSymbol =>
- if (clazz.info.findMember(member.name, 0, lateDEFERRED, stableOnly = false).alternatives contains imember)
- cloneAndAddMixinMember(mixinInterface, imember).asInstanceOf[TermSymbol] setAlias member
+ if (clazz.info.findMember(member.name, 0, 0L, stableOnly = false).alternatives contains member)
+ cloneAndAddMixinMember(mixinClass, member).asInstanceOf[TermSymbol] setAlias member
case _ =>
}
}
@@ -296,7 +262,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
val mixedInAccessor = cloneAndAddMixinMember(mixinClass, mixinMember)
if (mixinMember.isLazy) {
initializer(mixedInAccessor) = (
- implClass(mixinClass).info.decl(mixinMember.name)
+ mixinClass.info.decl(mixinMember.name)
orElse abort("Could not find initializer for " + mixinMember.name)
)
}
@@ -358,67 +324,16 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
// first complete the superclass with mixed in members
addMixedinMembers(clazz.superClass, unit)
- for (mc <- clazz.mixinClasses ; if mc hasFlag lateINTERFACE) {
+ for (mc <- clazz.mixinClasses ; if mc.isTrait) {
// @SEAN: adding trait tracking so we don't have to recompile transitive closures
unit.depends += mc
addLateInterfaceMembers(mc)
mixinTraitMembers(mc)
- mixinImplClassMembers(implClass(mc), mc)
+ mixinTraitForwarders(mc)
}
}
- /** The info transform for this phase does the following:
- * - The parents of every class are mapped from implementation class to interface
- * - Implementation classes become modules that inherit nothing
- * and that define all.
- */
- override def transformInfo(sym: Symbol, tp: Type): Type = tp match {
- case ClassInfoType(parents, decls, clazz) =>
- var parents1 = parents
- var decls1 = decls
- if (!clazz.isPackageClass) {
- exitingMixin(clazz.owner.info)
- if (clazz.isImplClass) {
- clazz setFlag lateMODULE
- var sourceModule = clazz.owner.info.decls.lookup(sym.name.toTermName)
- if (sourceModule == NoSymbol) {
- sourceModule = (
- clazz.owner.newModuleSymbol(sym.name.toTermName, sym.pos, MODULE)
- setModuleClass sym.asInstanceOf[ClassSymbol]
- )
- clazz.owner.info.decls enter sourceModule
- }
- else {
- sourceModule setPos sym.pos
- if (sourceModule.flags != MODULE) {
- log(s"!!! Directly setting sourceModule flags for $sourceModule from ${sourceModule.flagString} to MODULE")
- sourceModule.flags = MODULE
- }
- }
- sourceModule setInfo sym.tpe
- // Companion module isn't visible for anonymous class at this point anyway
- assert(clazz.sourceModule != NoSymbol || clazz.isAnonymousClass, s"$clazz has no sourceModule: $sym ${sym.tpe}")
- parents1 = List()
- decls1 = newScopeWith(decls.toList filter isImplementedStatically: _*)
- } else if (!parents.isEmpty) {
- parents1 = parents.head :: (parents.tail map toInterface)
- }
- }
- //decls1 = enteringPhase(phase.next)(newScopeWith(decls1.toList: _*))//debug
- if ((parents1 eq parents) && (decls1 eq decls)) tp
- else ClassInfoType(parents1, decls1, clazz)
-
- case MethodType(params, restp) =>
- toInterfaceMap(
- if (isImplementedStatically(sym)) {
- val ownerParam = sym.newSyntheticValueParam(toInterface(sym.owner.typeOfThis))
- MethodType(ownerParam :: params, restp)
- } else
- tp)
-
- case _ =>
- tp
- }
+ override def transformInfo(sym: Symbol, tp: Type): Type = tp
/** Return a map of single-use fields to the lazy value that uses them during initialization.
* Each field has to be private and defined in the enclosing class, and there must
@@ -466,10 +381,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
new MixinTransformer(unit)
class MixinTransformer(unit : CompilationUnit) extends Transformer {
- /** Within a static implementation method: the parameter referring to the
- * current object. Undefined everywhere else.
- */
- private var self: Symbol = _
/** The rootContext used for typing */
private val rootContext =
@@ -505,15 +416,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* (that is, every node is processed before its children).
* What transform does:
* - For every non-trait class, add all mixed in members to the class info.
- * - For every trait, add all late interface members to the class info
- * - For every static implementation method:
- * - remove override flag
- * - create a new method definition that also has a `self` parameter
- * (which comes first) Iuli: this position is assumed by tail call elimination
- * on a different receiver. Storing a new 'this' assumes it is located at
- * index 0 in the local variable table. See 'STORE_THIS' and GenASM.
- * - Map implementation class types in type-apply's to their interfaces
- * - Remove all fields in implementation classes
*/
private def preTransform(tree: Tree): Tree = {
val sym = tree.symbol
@@ -524,87 +426,19 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
if (!currentOwner.isTrait && !isPrimitiveValueClass(currentOwner))
addMixedinMembers(currentOwner, unit)
- else if (currentOwner hasFlag lateINTERFACE)
+ else if (currentOwner.isTrait)
addLateInterfaceMembers(currentOwner)
tree
- case DefDef(_, _, _, vparams :: Nil, _, _) =>
- if (currentOwner.isImplClass) {
- if (isImplementedStatically(sym)) {
- sym setFlag notOVERRIDE
- self = sym.newValueParameter(nme.SELF, sym.pos) setInfo toInterface(currentOwner.typeOfThis)
- val selfdef = ValDef(self) setType NoType
- copyDefDef(tree)(vparamss = List(selfdef :: vparams))
- }
- else EmptyTree
- }
- else {
- if (currentOwner.isTrait && sym.isSetter && !enteringPickler(sym.isDeferred)) {
- sym.addAnnotation(TraitSetterAnnotationClass)
- }
- tree
- }
- // !!! What is this doing, and why is it only looking for exactly
- // one type parameter? It would seem to be
- // "Map implementation class types in type-apply's to their interfaces"
- // from the comment on preTransform, but is there some way we should know
- // that impl class types in type applies can only appear in single
- // type parameter type constructors?
- case Apply(tapp @ TypeApply(fn, List(arg)), List()) =>
- if (arg.tpe.typeSymbol.isImplClass) {
- val ifacetpe = toInterface(arg.tpe)
- arg setType ifacetpe
- tapp setType MethodType(Nil, ifacetpe)
- tree setType ifacetpe
- }
- tree
- case ValDef(_, _, _, _) if currentOwner.isImplClass =>
- EmptyTree
+
case _ =>
+ if (currentOwner.isTrait && sym.isSetter && !enteringPickler(sym.isDeferred)) {
+ sym.addAnnotation(TraitSetterAnnotationClass)
+ }
tree
}
}
- /** Create an identifier which references self parameter.
- */
- private def selfRef(pos: Position) =
- gen.mkAttributedIdent(self) setPos pos
-
- /** Replace a super reference by this or the self parameter, depending
- * on whether we are in an implementation class or not.
- * Leave all other trees unchanged.
- */
- private def transformSuper(tree: Tree) = tree match {
- case Super(qual, _) =>
- transformThis(qual)
- case _ =>
- tree
- }
-
- /** Replace a this reference to the current implementation class by the self
- * parameter. Leave all other trees unchanged.
- */
- private def transformThis(tree: Tree) = tree match {
- case This(_) if tree.symbol.isImplClass =>
- assert(tree.symbol == currentOwner.enclClass)
- selfRef(tree.pos)
- case _ =>
- tree
- }
-
- /** Create a static reference to given symbol `sym` of the
- * form `M.sym` where M is the symbol's implementation module.
- */
- private def staticRef(sym: Symbol): Tree = {
- sym.owner.info //todo: needed?
- sym.owner.owner.info //todo: needed?
-
- if (sym.owner.sourceModule eq NoSymbol)
- abort(s"Cannot create static reference to $sym because ${sym.safeOwner} has no source module")
- else
- REF(sym.owner.sourceModule) DOT sym
- }
-
def needsInitAndHasOffset(sym: Symbol) =
needsInitFlag(sym) && (fieldOffset contains sym)
@@ -643,6 +477,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* - A super accessor for every super accessor in a mixin class
* - Forwarders for all methods that are implemented statically
* All superaccessors are completed with right-hand sides (@see completeSuperAccessor)
+ *
* @param clazz The class to which definitions are added
*/
private def addNewDefs(clazz: Symbol, stats: List[Tree]): List[Tree] = {
@@ -700,7 +535,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
*/
def completeSuperAccessor(stat: Tree) = stat match {
case DefDef(_, _, _, vparams :: Nil, _, EmptyTree) if stat.symbol.isSuperAccessor =>
- val body = atPos(stat.pos)(Apply(Select(Super(clazz, tpnme.EMPTY), stat.symbol.alias), vparams map (v => Ident(v.symbol))))
+ val body = atPos(stat.pos)(Apply(SuperSelect(clazz, stat.symbol.alias), vparams map (v => Ident(v.symbol))))
val pt = stat.symbol.tpe.resultType
copyDefDef(stat)(rhs = enteringMixin(transform(localTyper.typed(body, pt))))
@@ -887,7 +722,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
def isUnit = sym.tpe.resultType.typeSymbol == UnitClass
def isEmpty = stat.rhs == EmptyTree
- if (sym.isLazy && !isEmpty && !clazz.isImplClass) {
+ if (!clazz.isTrait && sym.isLazy && !isEmpty) {
assert(fieldOffset contains sym, sym)
deriveDefDef(stat) {
case t if isUnit => mkLazyDef(clazz, sym, List(t), UNIT, fieldOffset(sym))
@@ -898,7 +733,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
case t => t // pass specialized lazy vals through
}
}
- else if (needsInitFlag(sym) && !isEmpty && !clazz.hasFlag(IMPLCLASS | TRAIT)) {
+ else if (needsInitFlag(sym) && !isEmpty && !clazz.hasFlag(TRAIT)) {
assert(fieldOffset contains sym, sym)
deriveDefDef(stat)(rhs =>
(mkCheckedAccessor(clazz, _: Tree, fieldOffset(sym), stat.pos, sym))(
@@ -992,7 +827,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
// if it is a mixed-in lazy value, complete the accessor
if (getter.isLazy) {
val isUnit = isUnitGetter(getter)
- val initCall = Apply(staticRef(initializer(getter)), gen.mkAttributedThis(clazz) :: Nil)
+ val initCall = Apply(SuperSelect(clazz, initializer(getter)), Nil)
val selection = fieldAccess(getter)
val init = if (isUnit) initCall else atPos(getter.pos)(Assign(selection, initCall))
val returns = if (isUnit) UNIT else selection
@@ -1040,12 +875,11 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
// for all symbols `sym` in the class definition, which are mixed in:
for (sym <- clazz.info.decls ; if sym hasFlag MIXEDIN) {
- // if current class is a trait interface, add an abstract method for accessor `sym`
- if (clazz hasFlag lateINTERFACE) {
+ // if current class is a trait, add an abstract method for accessor `sym`
+ if (clazz.isTrait) {
addDefDef(sym)
- }
- // if class is not a trait add accessor definitions
- else if (!clazz.isTrait) {
+ } else {
+ // if class is not a trait add accessor definitions
if (isConcreteAccessor(sym)) {
// add accessor definitions
addDefDef(sym, {
@@ -1072,13 +906,20 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
}
else {
// add forwarders
- assert(sym.alias != NoSymbol, sym)
+ assert(sym.alias != NoSymbol, (sym, sym.debugFlagString, clazz))
// debuglog("New forwarder: " + sym.defString + " => " + sym.alias.defString)
- if (!sym.isMacro) addDefDef(sym, Apply(staticRef(sym.alias), gen.mkAttributedThis(clazz) :: sym.paramss.head.map(Ident)))
+ if (!sym.isMacro) addDefDef(sym, Apply(SuperSelect(clazz, sym.alias), sym.paramss.head.map(Ident(_))))
}
}
}
stats1 = add(stats1, newDefs.toList)
+ if (clazz.isTrait) stats1 =
+ stats1.filter {
+ case vd: ValDef =>
+ // TODO do we get here?
+ false
+ case _ => true
+ }
if (!clazz.isTrait) stats1 = stats1 map completeSuperAccessor
stats1
}
@@ -1113,14 +954,8 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* - refer to fields in some implementation class via an abstract method in the interface.
*/
private def postTransform(tree: Tree): Tree = {
- def siteWithinImplClass = currentOwner.enclClass.isImplClass
val sym = tree.symbol
- // change every node type that refers to an implementation class to its
- // corresponding interface, unless the node's symbol is an implementation class.
- if (tree.tpe.typeSymbol.isImplClass && ((sym eq null) || !sym.isImplClass))
- tree modifyType toInterface
-
tree match {
case templ @ Template(parents, self, body) =>
// change parents of templates to conform to parents in the symbol info
@@ -1130,87 +965,21 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
// add all new definitions to current class or interface
treeCopy.Template(tree, parents1, self, addNewDefs(currentOwner, body))
- // remove widening casts
- case Apply(TypeApply(Select(qual, _), targ :: _), _) if isCastSymbol(sym) && (qual.tpe <:< targ.tpe) =>
- qual
-
- case Apply(Select(qual, _), args) =>
- /* Changes `qual.m(args)` where m refers to an implementation
- * class method to Q.m(S, args) where Q is the implementation module of
- * `m` and S is the self parameter for the call, which
- * is determined as follows:
- * - if qual != super, qual itself
- * - if qual == super, and we are in an implementation class,
- * the current self parameter.
- * - if qual == super, and we are not in an implementation class, `this`
- */
- def staticCall(target: Symbol) = {
- def implSym = implClass(sym.owner).info.member(sym.name)
- assert(target ne NoSymbol,
- List(sym + ":", sym.tpe, sym.owner, implClass(sym.owner), implSym,
- enteringPrevPhase(implSym.tpe), phase) mkString " "
- )
- typedPos(tree.pos)(Apply(staticRef(target), transformSuper(qual) :: args))
- }
-
- if (isStaticOnly(sym)) {
- // change calls to methods which are defined only in implementation
- // classes to static calls of methods in implementation modules
- staticCall(sym)
- }
- else qual match {
- case Super(_, mix) =>
- // change super calls to methods in implementation classes to static calls.
- // Transform references super.m(args) as follows:
- // - if `m` refers to a trait, insert a static call to the corresponding static
- // implementation
- // - otherwise return tree unchanged
- assert(
- !(mix == tpnme.EMPTY && siteWithinImplClass),
- "illegal super in trait: " + currentOwner.enclClass + " " + tree
- )
+ case Select(qual, name) if sym.owner.isTrait && !sym.isMethod =>
+ // refer to fields in some trait an abstract getter in the interface.
+ val ifaceGetter = sym getterIn sym.owner
- if (sym.owner hasFlag lateINTERFACE) {
- if (sym.hasAccessorFlag) {
- assert(args.isEmpty, args)
- val sym1 = sym.overridingSymbol(currentOwner.enclClass)
- typedPos(tree.pos)((transformSuper(qual) DOT sym1)())
- }
- else {
- staticCall(enteringPrevPhase(sym.overridingSymbol(implClass(sym.owner))))
- }
- }
- else {
- assert(!siteWithinImplClass, currentOwner.enclClass)
- tree
- }
- case _ =>
- tree
- }
-
- case This(_) =>
- transformThis(tree)
-
- case Select(Super(_, _), name) =>
- tree
-
- case Select(qual, name) if sym.owner.isImplClass && !isStaticOnly(sym) =>
- assert(!sym.isMethod, "no method allowed here: %s%s %s".format(sym, sym.isImplOnly, sym.flagString))
- // refer to fields in some implementation class via an abstract
- // getter in the interface.
- val iface = toInterface(sym.owner.tpe).typeSymbol
- val ifaceGetter = sym getterIn iface
-
- if (ifaceGetter == NoSymbol) abort("No getter for " + sym + " in " + iface)
+ if (ifaceGetter == NoSymbol) abort("No getter for " + sym + " in " + sym.owner)
else typedPos(tree.pos)((qual DOT ifaceGetter)())
case Assign(Apply(lhs @ Select(qual, _), List()), rhs) =>
- // assign to fields in some implementation class via an abstract
- // setter in the interface.
- def setter = lhs.symbol.setterIn(toInterface(lhs.symbol.owner.tpe).typeSymbol) setPos lhs.pos
+ // assign to fields in some trait via an abstract setter in the interface.
+ // Note that the case above has added the empty application.
+ val setter = lhs.symbol.setterIn(lhs.symbol.owner.tpe.typeSymbol) setPos lhs.pos
typedPos(tree.pos)((qual DOT setter)(rhs))
+
case _ =>
tree
}
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index eea1f53cbc..40a988ee94 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -374,8 +374,9 @@ abstract class UnCurry extends InfoTransform
*/
private def replaceElidableTree(tree: Tree): Tree = {
tree match {
- case DefDef(_,_,_,_,_,_) =>
- deriveDefDef(tree)(rhs => Block(Nil, gen.mkZero(rhs.tpe)) setType rhs.tpe) setSymbol tree.symbol setType tree.tpe
+ case DefDef(_,_,_,_,_,rhs) =>
+ val rhs1 = if (rhs == EmptyTree) rhs else Block(Nil, gen.mkZero(rhs.tpe)) setType rhs.tpe
+ deriveDefDef(tree)(_ => rhs1) setSymbol tree.symbol setType tree.tpe
case _ =>
gen.mkZero(tree.tpe) setType tree.tpe
}
@@ -744,7 +745,7 @@ abstract class UnCurry extends InfoTransform
case Packed(param, tempVal) => (param, tempVal)
}.unzip
- val rhs1 = if (tempVals.isEmpty) rhs else {
+ val rhs1 = if (rhs == EmptyTree || tempVals.isEmpty) rhs else {
localTyper.typedPos(rhs.pos) {
// Patch the method body to refer to the temp vals
val rhsSubstituted = rhs.substituteSymbols(packedParams map (_.symbol), tempVals map (_.symbol))
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index cb4eab335b..3e60ef37c4 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -723,7 +723,6 @@ trait Contexts { self: Analyzer =>
( (ab.isTerm || ab == rootMirror.RootClass)
|| (accessWithin(ab) || accessWithinLinked(ab)) &&
( !sym.isLocalToThis
- || sym.owner.isImplClass // allow private local accesses to impl classes
|| sym.isProtected && isSubThisType(pre, sym.owner)
|| pre =:= sym.owner.thisType
)
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index 1bc5daac65..5062289ed1 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -469,8 +469,7 @@ trait NamesDefaults { self: Analyzer =>
else {
// isClass also works for methods in objects, owner is the ModuleClassSymbol
if (param.owner.owner.isClass) {
- // .toInterface: otherwise we get the method symbol of the impl class
- param.owner.owner.toInterface.info.member(defGetterName)
+ param.owner.owner.info.member(defGetterName)
} else {
// the owner of the method is another method. find the default
// getter in the context.
diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
index f6ee0c47a5..990edcd86d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
@@ -111,8 +111,6 @@ abstract class TreeCheckers extends Analyzer {
newSyms += sym
else if (prevTrees exists (t => (t eq tree) || (t.symbol == sym)))
()
- else if (prevTrees exists (_.symbol.owner == sym.owner.implClass))
- errorFn("Noticed " + ownerstr(sym) + " moving to implementation class.")
else {
val s1 = (prevTrees map wholetreestr).sorted.distinct
val s2 = wholetreestr(tree)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 24da2d09c5..9446a45c06 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -4651,10 +4651,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
def findMixinSuper(site: Type): Type = {
var ps = site.parents filter (_.typeSymbol.name == mix)
if (ps.isEmpty)
- ps = site.parents filter (_.typeSymbol.toInterface.name == mix)
+ ps = site.parents filter (_.typeSymbol.name == mix)
if (ps.isEmpty) {
debuglog("Fatal: couldn't find site " + site + " in " + site.parents.map(_.typeSymbol.name))
- if (phase.erasedTypes && context.enclClass.owner.isImplClass) {
+ if (phase.erasedTypes && context.enclClass.owner.isTrait) {
// the reference to super class got lost during erasure
restrictionError(tree.pos, unit, "traits may not select fields or methods from super[C] where C is a class")
ErrorType