|
| 1 | +package dotty.tools.dotc |
| 2 | +package transform |
| 3 | + |
| 4 | +import core._ |
| 5 | +import TreeTransforms._ |
| 6 | +import Contexts.Context |
| 7 | +import Flags._ |
| 8 | +import SymUtils._ |
| 9 | +import Symbols._ |
| 10 | +import SymDenotations._ |
| 11 | +import Types._ |
| 12 | +import Decorators._ |
| 13 | +import DenotTransformers._ |
| 14 | +import StdNames._ |
| 15 | +import NameOps._ |
| 16 | +import ast.Trees._ |
| 17 | + |
| 18 | +/** This phase augments Scala2 traits with implementation classes and with additional members |
| 19 | + * needed for mixin composition. |
| 20 | + * These symbols would have been added between Unpickling and Mixin in the Scala2 pipeline. |
| 21 | + * Specifcally, it adds |
| 22 | + * |
| 23 | + * - an implementation class which defines a trait constructor and trait method implementations |
| 24 | + * - trait setters for vals defined in traits |
| 25 | + * |
| 26 | + * Furthermore, it expands the names of all private getters and setters in the trait and makes |
| 27 | + * them not-private. |
| 28 | + */ |
| 29 | +class AugmentScala2Traits extends MiniPhaseTransform with IdentityDenotTransformer with FullParameterization { thisTransform => |
| 30 | + import ast.tpd._ |
| 31 | + |
| 32 | + override def phaseName: String = "augmentScala2Traits" |
| 33 | + |
| 34 | + override def rewiredTarget(referenced: Symbol, derived: Symbol)(implicit ctx: Context) = NoSymbol |
| 35 | + |
| 36 | + override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo) = { |
| 37 | + val cls = impl.symbol.owner.asClass |
| 38 | + for (mixin <- cls.mixins) |
| 39 | + if (mixin.is(Scala2x)) |
| 40 | + augmentScala2Trait(mixin, cls) |
| 41 | + impl |
| 42 | + } |
| 43 | + |
| 44 | + private def augmentScala2Trait(mixin: ClassSymbol, cls: ClassSymbol)(implicit ctx: Context): Unit = { |
| 45 | + if (mixin.implClass.is(Scala2x)) () // nothing to do, mixin was already augmented |
| 46 | + else { |
| 47 | + //println(i"creating new implclass for $mixin ${mixin.implClass}") |
| 48 | + val ops = new MixinOps(cls, thisTransform) |
| 49 | + import ops._ |
| 50 | + |
| 51 | + val implClass = ctx.newCompleteClassSymbol( |
| 52 | + owner = mixin.owner, |
| 53 | + name = mixin.name.implClassName, |
| 54 | + flags = Abstract | Scala2x, |
| 55 | + parents = defn.ObjectClass.typeRef :: Nil, |
| 56 | + assocFile = mixin.assocFile).enteredAfter(thisTransform) |
| 57 | + |
| 58 | + def implMethod(meth: TermSymbol): Symbol = { |
| 59 | + val mold = |
| 60 | + if (meth.isConstructor) |
| 61 | + meth.copySymDenotation( |
| 62 | + name = nme.IMPLCLASS_CONSTRUCTOR, |
| 63 | + info = MethodType(Nil, defn.UnitType)) |
| 64 | + else meth.ensureNotPrivate |
| 65 | + meth.copy( |
| 66 | + owner = implClass, |
| 67 | + name = mold.name.asTermName, |
| 68 | + flags = Method | JavaStatic | mold.flags & ExpandedName, |
| 69 | + info = fullyParameterizedType(mold.info, mixin)) |
| 70 | + } |
| 71 | + |
| 72 | + def traitSetter(getter: TermSymbol) = { |
| 73 | + val separator = if (getter.is(Private)) nme.EXPAND_SEPARATOR else nme.TRAIT_SETTER_SEPARATOR |
| 74 | + val expandedGetterName = |
| 75 | + if (getter.is(ExpandedName)) getter.name |
| 76 | + else getter.name.expandedName(getter.owner, separator) |
| 77 | + getter.copy( |
| 78 | + name = expandedGetterName.setterName, |
| 79 | + flags = Method | Accessor | ExpandedName, |
| 80 | + info = MethodType(getter.info.resultType :: Nil, defn.UnitType)) |
| 81 | + } |
| 82 | + |
| 83 | + for (sym <- mixin.info.decls) { |
| 84 | + if (needsForwarder(sym) || sym.isConstructor || sym.isGetter && sym.is(Lazy)) |
| 85 | + implClass.enter(implMethod(sym.asTerm)) |
| 86 | + if (sym.isGetter && !sym.is(LazyOrDeferred) && !sym.setter.exists) |
| 87 | + traitSetter(sym.asTerm).enteredAfter(thisTransform) |
| 88 | + if (sym.is(PrivateAccessor, butNot = ExpandedName) && |
| 89 | + (sym.isGetter || sym.isSetter)) // strangely, Scala 2 fields are also methods that have Accessor set. |
| 90 | + sym.ensureNotPrivate.installAfter(thisTransform) |
| 91 | + } |
| 92 | + ctx.log(i"Scala2x trait decls of $mixin = ${mixin.info.decls.toList.map(_.showDcl)}%\n %") |
| 93 | + ctx.log(i"Scala2x impl decls of $mixin = ${implClass.info.decls.toList.map(_.showDcl)}%\n %") |
| 94 | + } |
| 95 | + } |
| 96 | +} |
0 commit comments