diff options
Diffstat (limited to 'compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala')
-rw-r--r-- | compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala b/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala new file mode 100644 index 000000000..9c01aaa9a --- /dev/null +++ b/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala @@ -0,0 +1,101 @@ +package dotty.tools.dotc +package transform + +import core._ +import TreeTransforms._ +import Contexts.Context +import Flags._ +import SymUtils._ +import Symbols._ +import SymDenotations._ +import Types._ +import Decorators._ +import DenotTransformers._ +import Annotations._ +import StdNames._ +import NameOps._ +import ast.Trees._ + +/** This phase augments Scala2 traits with implementation classes and with additional members + * needed for mixin composition. + * These symbols would have been added between Unpickling and Mixin in the Scala2 pipeline. + * Specifcally, it adds + * + * - an implementation class which defines a trait constructor and trait method implementations + * - trait setters for vals defined in traits + * + * Furthermore, it expands the names of all private getters and setters as well as super accessors in the trait and makes + * them not-private. + */ +class AugmentScala2Traits extends MiniPhaseTransform with IdentityDenotTransformer with FullParameterization { thisTransform => + import ast.tpd._ + + override def phaseName: String = "augmentScala2Traits" + + override def rewiredTarget(referenced: Symbol, derived: Symbol)(implicit ctx: Context) = NoSymbol + + override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo) = { + val cls = impl.symbol.owner.asClass + for (mixin <- cls.mixins) + if (mixin.is(Scala2x)) + augmentScala2Trait(mixin, cls) + impl + } + + private def augmentScala2Trait(mixin: ClassSymbol, cls: ClassSymbol)(implicit ctx: Context): Unit = { + if (mixin.implClass.is(Scala2x)) () // nothing to do, mixin was already augmented + else { + //println(i"creating new implclass for $mixin ${mixin.implClass}") + val ops = new MixinOps(cls, thisTransform) + import ops._ + + val implClass = ctx.newCompleteClassSymbol( + owner = mixin.owner, + name = mixin.name.implClassName, + flags = Abstract | Scala2x, + parents = defn.ObjectType :: Nil, + assocFile = mixin.assocFile).enteredAfter(thisTransform) + + def implMethod(meth: TermSymbol): Symbol = { + val mold = + if (meth.isConstructor) + meth.copySymDenotation( + name = nme.TRAIT_CONSTRUCTOR, + info = MethodType(Nil, defn.UnitType)) + else meth.ensureNotPrivate + meth.copy( + owner = implClass, + name = mold.name.asTermName, + flags = Method | JavaStatic | mold.flags & ExpandedName, + info = fullyParameterizedType(mold.info, mixin)) + } + + def traitSetter(getter: TermSymbol) = + getter.copy( + name = getter.ensureNotPrivate.name + .expandedName(getter.owner, nme.TRAIT_SETTER_SEPARATOR) + .asTermName.setterName, + flags = Method | Accessor | ExpandedName, + info = MethodType(getter.info.resultType :: Nil, defn.UnitType)) + + for (sym <- mixin.info.decls) { + if (needsForwarder(sym) || sym.isConstructor || sym.isGetter && sym.is(Lazy) || sym.is(Method, butNot = Deferred)) + implClass.enter(implMethod(sym.asTerm)) + if (sym.isGetter) + if (sym.is(Lazy)) { + if (!sym.hasAnnotation(defn.VolatileAnnot)) + sym.addAnnotation(Annotation(defn.VolatileAnnot, Nil)) + } + else if (!sym.is(Deferred) && !sym.setter.exists && + !sym.info.resultType.isInstanceOf[ConstantType]) + traitSetter(sym.asTerm).enteredAfter(thisTransform) + if ((sym.is(PrivateAccessor, butNot = ExpandedName) && + (sym.isGetter || sym.isSetter)) // strangely, Scala 2 fields are also methods that have Accessor set. + || sym.is(SuperAccessor)) // scala2 superaccessors are pickled as private, but are compiled as public expanded + sym.ensureNotPrivate.installAfter(thisTransform) + } + ctx.log(i"Scala2x trait decls of $mixin = ${mixin.info.decls.toList.map(_.showDcl)}%\n %") + ctx.log(i"Scala2x impl decls of $mixin = ${implClass.info.decls.toList.map(_.showDcl)}%\n %") + } + } +} |