diff options
-rw-r--r-- | src/dotty/tools/dotc/core/NameOps.scala | 32 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Phases.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/StdNames.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/SymDenotations.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/GettersSetters.scala | 118 |
5 files changed, 147 insertions, 13 deletions
diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala index b18f708ed..beb3142d3 100644 --- a/src/dotty/tools/dotc/core/NameOps.scala +++ b/src/dotty/tools/dotc/core/NameOps.scala @@ -68,10 +68,11 @@ object NameOps { def isProtectedAccessorName = name startsWith PROTECTED_PREFIX def isReplWrapperName = name containsSlice INTERPRETER_IMPORT_WRAPPER def isSetterName = name endsWith SETTER_SUFFIX - def isTraitSetterName = isSetterName && (name containsSlice TRAIT_SETTER_SEPARATOR) + def isTraitSetterName = isSetterName && (name containsSlice TRAIT_SETTER_PREFIX) def isSingletonName = name endsWith SINGLETON_SUFFIX def isModuleClassName = name endsWith MODULE_SUFFIX def isImportName = name startsWith IMPORT + def isFieldName = name endsWith LOCAL_SUFFIX def isInheritedName = name.length > 0 && name.head == '(' && name.startsWith(nme.INHERITED) def isDefaultGetterName = name.isTermName && name.asTermName.defaultGetterIndex >= 0 @@ -223,23 +224,36 @@ object NameOps { implicit class TermNameDecorator(val name: TermName) extends AnyVal { import nme._ - /** The expanded setter name of `name` relative to this class `base` - */ - def expandedSetterName(base: Symbol)(implicit ctx: Context): TermName = - name.expandedName(base, separator = TRAIT_SETTER_SEPARATOR) + def traitSetterName: TermName = + nme.TRAIT_SETTER_PREFIX ++ setterName + + def setterName: TermName = + if (name.isFieldName) name.fieldToGetter.setterName + else name ++ SETTER_SUFFIX + + def getterName: TermName = + if (name.isFieldName) fieldToGetter + else setterToGetter - def setterName: TermName = name ++ SETTER_SUFFIX + def fieldName: TermName = + if (name.isSetterName) getterName.fieldName + else name ++ LOCAL_SUFFIX - def setterToGetter: TermName = { - val p = name.indexOfSlice(TRAIT_SETTER_SEPARATOR) + private def setterToGetter: TermName = { + val p = name.indexOfSlice(TRAIT_SETTER_PREFIX) if (p >= 0) - (name drop (p + TRAIT_SETTER_SEPARATOR.length)).asTermName.setterToGetter + (name drop (p + TRAIT_SETTER_PREFIX.length)).asTermName.getterName else { assert(name.endsWith(SETTER_SUFFIX), name + " is referenced as a setter but has wrong name format") name.take(name.length - SETTER_SUFFIX.length).asTermName } } + def fieldToGetter: TermName = { + assert(name.isFieldName) + name.take(name.length - LOCAL_SUFFIX.length).asTermName + } + /** Nominally, name$default$N, encoded for <init> * @param Post the parameters position. * @note Default getter name suffixes start at 1, so `pos` has to be adjusted by +1 diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala index 53c193994..caeb18f57 100644 --- a/src/dotty/tools/dotc/core/Phases.scala +++ b/src/dotty/tools/dotc/core/Phases.scala @@ -9,7 +9,7 @@ import Denotations._ import config.Printers._ import scala.collection.mutable.{ListBuffer, ArrayBuffer} import dotty.tools.dotc.transform.TreeTransforms.{TreeTransformer, MiniPhase, TreeTransform} -import dotty.tools.dotc.transform.{ExplicitOuter, TreeTransforms, Erasure, Flatten} +import dotty.tools.dotc.transform.{TreeTransforms, ExplicitOuter, Erasure, Flatten, GettersSetters} import Periods._ import typer.{FrontEnd, RefChecks} import ast.tpd @@ -169,12 +169,14 @@ object Phases { private val erasureCache = new PhaseCache(classOf[Erasure]) private val flattenCache = new PhaseCache(classOf[Flatten]) private val explicitOuterCache = new PhaseCache(classOf[ExplicitOuter]) + private val gettersSettersCache = new PhaseCache(classOf[GettersSetters]) def typerPhase = typerCache.phase def refchecksPhase = refChecksCache.phase def erasurePhase = erasureCache.phase def flattenPhase = flattenCache.phase def explicitOuter = explicitOuterCache.phase + def gettersSettersPhase = gettersSettersCache.phase def isAfterTyper(phase: Phase): Boolean = phase.id > typerPhase.id } diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala index 4f2fe9dba..65eea1128 100644 --- a/src/dotty/tools/dotc/core/StdNames.scala +++ b/src/dotty/tools/dotc/core/StdNames.scala @@ -119,7 +119,7 @@ object StdNames { val SINGLETON_SUFFIX: N = ".type" val SPECIALIZED_SUFFIX: N = "$sp" val SUPER_PREFIX: N = "super$" - val TRAIT_SETTER_SEPARATOR: N = "$_setter_$" + val TRAIT_SETTER_PREFIX: N = "_setter_$" val WHILE_PREFIX: N = "while$" // value types (and AnyRef) are all used as terms as well @@ -226,7 +226,7 @@ object StdNames { val LAZY_LOCAL: N = "$lzy" val LAZY_FIELD_OFFSET: N = "OFFSET$" val LAZY_SLOW_SUFFIX: N = "$lzycompute" - val LOCAL_SUFFIX: N = " " + val LOCAL_SUFFIX: N = "$$local" val UNIVERSE_BUILD_PREFIX: N = "$u.build." val UNIVERSE_BUILD: N = "$u.build" val UNIVERSE_PREFIX: N = "$u." diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 4d0513abf..da83811f1 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -612,7 +612,7 @@ object SymDenotations { /** The field accessed by this getter or setter, or if it does not exist, the getter */ def accessedFieldOrGetter(implicit ctx: Context): Symbol = { - val fieldName = if (isSetter) name.asTermName.setterToGetter else name + val fieldName = if (isSetter) name.asTermName.getterName else name val d = owner.info.decl(fieldName) val field = d.suchThat(!_.is(Method)).symbol def getter = d.suchThat(_.info.isParameterless).symbol diff --git a/src/dotty/tools/dotc/transform/GettersSetters.scala b/src/dotty/tools/dotc/transform/GettersSetters.scala new file mode 100644 index 000000000..05c706419 --- /dev/null +++ b/src/dotty/tools/dotc/transform/GettersSetters.scala @@ -0,0 +1,118 @@ +package dotty.tools.dotc +package transform + +import core._ +import DenotTransformers.SymTransformer +import Phases.Phase +import Contexts.Context +import SymDenotations.SymDenotation +import Types._ +import Symbols._ +import SymUtils._ +import Constants._ +import ast.Trees._ +import TreeTransforms._ +import NameOps._ +import Flags._ +import Decorators._ + +/** Performs the following rewritings: + * + * val x: T = e + * --> private val x_L: T = e + * <stable> def x: T = x_L (if in class) + * --> private notJavaPrivate var x_L: T = e + * <stable> def x: T = x_L + * private notJavaPrivate def x_=(x: T): Unit = x_L = x (if in trait) + * var x: T = e + * --> private var x_L: T = e + * def x: T = x_L + * def x_=(x: T): Unit = x_L = x (if in class or trait) + * lazy val x: T = e + * --> lazy def x = e + * + * Furthermore, assignements to mutable vars are replaced by setter calls + * + * p.x = e + * --> p.x_=(e) + */ +class GettersSetters extends MiniPhaseTransform with SymTransformer { thisTransform => + import ast.tpd._ + + override def phaseName = "gettersSetters" + + override def treeTransformPhase = thisTransform.next + + override def transformSym(d: SymDenotation)(implicit ctx: Context): SymDenotation = { + /* def noGetterNeeded = + d.is(Method | Param | JavaDefined) || + d.initial.asInstanceOf[SymDenotation].is(PrivateLocal) && !d.owner.is(Trait) || + d.is(Module) && d.isStatic || + d.isSelfSym + if (d.isTerm && (d.owner.isClass || d.is(Lazy)) && d.info.isValueType && !noGetterNeeded) { + val maybeStable = if (d.isStable) Stable else EmptyFlags + if (d.name.toString == "_") println(i"make accessor $d in ${d.owner} ${d.symbol.id}") + d.copySymDenotation( + initFlags = d.flags | maybeStable | AccessorCreationFlags, + info = ExprType(d.info)) + } + else */ d + } +/* + override def transformValDef(tree: ValDef)(implicit ctx: Context, info: TransformerInfo): Tree = { + if (tree.symbol is Method) { + val getter = tree.symbol.asTerm + assert(getter is Accessor) + if (getter.is(Lazy | Deferred | ParamAccessor)) DefDef(getter, tree.rhs) + else { + val inTrait = getter.owner.is(Trait) + val maybePrivate = + if (inTrait) Private | NotJavaPrivate + else if (getter.owner.isClass) Private + else EmptyFlags + val maybeMutable = + if (inTrait || getter.is(Mutable)) Mutable + else EmptyFlags + val field = ctx.newSymbol( + owner = ctx.owner, + name = getter.name.fieldName, + flags = maybePrivate | maybeMutable, + info = getter.info.resultType).enteredAfter(thisTransform) + assert(tree.rhs.tpe.exists, tree.show) + val fieldDef = + cpy.ValDef(tree)( + mods = tree.mods & EmptyFlags | field.flags, + name = field.name, + rhs = tree.rhs.changeOwner(getter, field).ensureConforms(field.info.widen) + ).withType(field.valRef) + val rhs = ref(field) + assert(rhs.hasType) + val getterDef = DefDef(getter, rhs.ensureConforms(getter.info.widen)) + if (!getter.is(Mutable) && inTrait) { // add a setter anyway, will be needed for mixin + val setter = ctx.newSymbol( + owner = ctx.owner, + name = getter.name.traitSetterName, + flags = (getter.flags & AccessFlags) | Accessor | maybePrivate, + info = MethodType(field.info :: Nil, defn.UnitType)).enteredAfter(thisTransform) + val setterDef = DefDef(setter.asTerm, vrefss => Assign(ref(field), vrefss.head.head)) + Thicket(fieldDef, getterDef, setterDef) + } + else Thicket(fieldDef, getterDef) + } + } + else tree + } + + override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = + if (tree.symbol.isSetter && !tree.symbol.is(Deferred | ParamAccessor)) { + val Literal(Constant(())) = tree.rhs + val initializer = Assign(ref(tree.symbol.field), ref(tree.vparamss.head.head.symbol)) + assert(initializer.hasType) + cpy.DefDef(tree)(rhs = initializer) + } + else tree + + override def transformAssign(tree: Assign)(implicit ctx: Context, info: TransformerInfo): Tree = + if (tree.lhs.symbol is Method) tree.lhs.becomes(tree.rhs) + else tree*/ +}
\ No newline at end of file |