summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/transform/Mixin.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/Mixin.scala')
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala28
1 files changed, 26 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 6df0b992ed..d62b77dac2 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -130,6 +130,10 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
*/
def addMember(clazz: Symbol, member: Symbol): Symbol = {
debuglog(s"mixing into $clazz: ${member.defString}")
+ // This attachment is used to instruct the backend about which methids in traits require
+ // a static trait impl method. We remove this from the new symbol created for the method
+ // mixed into the subclass.
+ member.removeAttachment[NeedStaticImpl.type]
clazz.info.decls enter member setFlag MIXEDIN resetFlag JAVA_DEFAULTMETHOD
}
def cloneAndAddMember(mixinClass: Symbol, mixinMember: Symbol, clazz: Symbol): Symbol =
@@ -344,6 +348,10 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
reporter.error(clazz.pos, "Member %s of mixin %s is missing a concrete super implementation.".format(
mixinMember.alias, mixinClass))
case alias1 =>
+ if (alias1.owner.isJavaDefined && alias1.owner.isInterface && !clazz.parentSymbols.contains(alias1.owner)) {
+ val suggestedParent = exitingTyper(clazz.info.baseType(alias1.owner))
+ reporter.error(clazz.pos, s"Unable to implement a super accessor required by trait ${mixinClass.name} unless $suggestedParent is directly extended by $clazz.")
+ }
superAccessor.asInstanceOf[TermSymbol] setAlias alias1
}
}
@@ -1001,13 +1009,20 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
val parents1 = currentOwner.info.parents map (t => TypeTree(t) setPos tree.pos)
// mark fields which can be nulled afterward
lazyValNullables = nullableFields(templ) withDefaultValue Set()
+ // Remove bodies of accessors in traits - TODO: after PR #5141 (fields refactoring), this might be a no-op
val bodyEmptyAccessors = if (!sym.enclClass.isTrait) body else body mapConserve {
case dd: DefDef if dd.symbol.isAccessor && !dd.symbol.isLazy =>
deriveDefDef(dd)(_ => EmptyTree)
case tree => tree
}
// add all new definitions to current class or interface
- treeCopy.Template(tree, parents1, self, addNewDefs(currentOwner, bodyEmptyAccessors))
+ val body1 = addNewDefs(currentOwner, bodyEmptyAccessors)
+ body1 foreach {
+ case dd: DefDef if isTraitMethodRequiringStaticImpl(dd) =>
+ dd.symbol.updateAttachment(NeedStaticImpl)
+ case _ =>
+ }
+ treeCopy.Template(tree, parents1, self, body1)
case Select(qual, name) if sym.owner.isTrait && !sym.isMethod =>
// refer to fields in some trait an abstract getter in the interface.
@@ -1023,7 +1038,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
typedPos(tree.pos)((qual DOT setter)(rhs))
-
case _ =>
tree
}
@@ -1042,4 +1056,14 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
finally localTyper = saved
}
}
+
+ private def isTraitMethodRequiringStaticImpl(dd: DefDef): Boolean = {
+ val sym = dd.symbol
+ dd.rhs.nonEmpty &&
+ sym.owner.isTrait &&
+ !sym.isPrivate && // no need to put implementations of private methods into a static method
+ !sym.hasFlag(Flags.STATIC)
+ }
+
+ case object NeedStaticImpl extends PlainAttachment
}