aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-10-07 09:27:56 +0200
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2014-10-12 10:49:43 +0200
commitafd9a66453848412ae0a974ddd475da2b0d846bf (patch)
tree34c5207a6b388684a9e92a1ae5eca2526991d7f4 /src/dotty/tools/dotc
parent5de255637589b800ffc99ddb3453ccd651bfafc9 (diff)
downloaddotty-afd9a66453848412ae0a974ddd475da2b0d846bf.tar.gz
dotty-afd9a66453848412ae0a974ddd475da2b0d846bf.tar.bz2
dotty-afd9a66453848412ae0a974ddd475da2b0d846bf.zip
rename AddGetters -> GettersSetters
... and add a gettersSettersPhase to Context.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/core/NameOps.scala32
-rw-r--r--src/dotty/tools/dotc/core/Phases.scala4
-rw-r--r--src/dotty/tools/dotc/core/StdNames.scala4
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala2
-rw-r--r--src/dotty/tools/dotc/transform/GettersSetters.scala118
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