aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/ast
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2017-04-05 17:09:15 +0200
committerMartin Odersky <odersky@gmail.com>2017-04-05 17:09:22 +0200
commitf7027732a1d1e92f4d7525f2a984a24fdb7a0053 (patch)
treed1420d55db9013c536c7bba69ba03b8f9a4c2639 /compiler/src/dotty/tools/dotc/ast
parent993834473c39b409bb2e21838a0e69fcc5fb4757 (diff)
downloaddotty-f7027732a1d1e92f4d7525f2a984a24fdb7a0053.tar.gz
dotty-f7027732a1d1e92f4d7525f2a984a24fdb7a0053.tar.bz2
dotty-f7027732a1d1e92f4d7525f2a984a24fdb7a0053.zip
Implementation of proposal changes
- rename utility methods - generate utility methods also for object cases
Diffstat (limited to 'compiler/src/dotty/tools/dotc/ast')
-rw-r--r--compiler/src/dotty/tools/dotc/ast/Desugar.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala119
2 files changed, 76 insertions, 45 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
index 80da75678..8499330fb 100644
--- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
@@ -395,7 +395,7 @@ object desugar {
.withMods(synthetic) :: Nil
}
- val enumTagMeths = if (isEnumCase) enumTagMeth :: Nil else Nil
+ val enumTagMeths = if (isEnumCase) enumTagMeth(CaseKind.Class)._1 :: Nil else Nil
copyMeths ::: enumTagMeths ::: productElemMeths.toList
}
else Nil
diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala
index ae4ba23d5..e051824a1 100644
--- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala
+++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala
@@ -10,26 +10,26 @@ import collection.mutable.ListBuffer
import util.Property
import typer.ErrorReporting._
+/** Helper methods to desugar enums */
object DesugarEnums {
import untpd._
import desugar.DerivedFromParamTree
- /** Attachment containing: The number of enum cases seen so far, and whether a
- * simple enum case was already seen.
- */
- val EnumCaseCount = new Property.Key[(Int, Boolean)]
+ @sharable object CaseKind extends Enumeration {
+ val Simple, Object, Class = Value
+ }
- def enumClass(implicit ctx: Context) = ctx.owner.linkedClass
+ /** Attachment containing the number of enum cases and the smallest kind that was seen so far. */
+ val EnumCaseCount = new Property.Key[(Int, CaseKind.Value)]
- def nextEnumTag(isSimpleCase: Boolean)(implicit ctx: Context): (Int, Boolean) = {
- val (count, simpleSeen) = ctx.tree.removeAttachment(EnumCaseCount).getOrElse((0, false))
- ctx.tree.pushAttachment(EnumCaseCount, (count + 1, simpleSeen | isSimpleCase))
- (count, simpleSeen)
- }
+ /** the enumeration class that is a companion of the current object */
+ def enumClass(implicit ctx: Context) = ctx.owner.linkedClass
+ /** Is this an enum case that's situated in a companion object of an enum class? */
def isLegalEnumCase(tree: MemberDef)(implicit ctx: Context): Boolean =
tree.mods.hasMod[Mod.EnumCase] && enumCaseIsLegal(tree)
+ /** Is enum case `tree` situated in a companion object of an enum class? */
def enumCaseIsLegal(tree: Tree)(implicit ctx: Context): Boolean = (
ctx.owner.is(ModuleClass) && enumClass.derivesFrom(defn.EnumClass)
|| { ctx.error(em"case not allowed here, since owner ${ctx.owner} is not an `enum' object", tree.pos)
@@ -81,59 +81,89 @@ object DesugarEnums {
TypeTree(enumClass.typeRef.appliedTo(targs)).withPos(pos)
}
- def enumTagMeth(implicit ctx: Context) =
- DefDef(nme.enumTag, Nil, Nil, TypeTree(),
- Literal(Constant(nextEnumTag(isSimpleCase = false)._1)))
-
+ /** A type tree referring to `enumClass` */
def enumClassRef(implicit ctx: Context) = TypeTree(enumClass.typeRef)
+ /** Add implied flags to an enum class or an enum case */
def addEnumFlags(cdef: TypeDef)(implicit ctx: Context) =
if (cdef.mods.hasMod[Mod.Enum]) cdef.withFlags(cdef.mods.flags | Abstract | Sealed)
else if (isLegalEnumCase(cdef)) cdef.withFlags(cdef.mods.flags | Final)
else cdef
+ private def valuesDot(name: String) = Select(Ident(nme.DOLLAR_VALUES), name.toTermName)
+ private def registerCall = Apply(valuesDot("register"), This(EmptyTypeIdent) :: Nil)
+
/** The following lists of definitions for an enum type E:
*
* private val $values = new EnumValues[E]
- * def valueOf = $values.fromInt
- * def withName = $values.fromName
- * def values = $values.values
- *
+ * def enumValue = $values.fromInt
+ * def enumValueNamed = $values.fromName
+ * def enumValues = $values.values
+ */
+ private def enumScaffolding(implicit ctx: Context): List[Tree] = {
+ val enumType = enumClass.typeRef.appliedTo(enumClass.typeParams.map(_ => TypeBounds.empty))
+ def enumDefDef(name: String, select: String) =
+ DefDef(name.toTermName, Nil, Nil, TypeTree(), valuesDot(select))
+ val privateValuesDef =
+ ValDef(nme.DOLLAR_VALUES, TypeTree(),
+ New(TypeTree(defn.EnumValuesType.appliedTo(enumType :: Nil)), ListOfNil))
+ .withFlags(Private)
+ val valueOfDef = enumDefDef("enumValue", "fromInt")
+ val withNameDef = enumDefDef("enumValueNamed", "fromName")
+ val valuesDef = enumDefDef("enumValues", "values")
+ List(privateValuesDef, valueOfDef, withNameDef, valuesDef)
+ }
+
+ /** A creation method for a value of enum type `E`, which is defined as follows:
+ *
* private def $new(tag: Int, name: String) = new E {
* def enumTag = tag
* override def toString = name
* $values.register(this)
* }
*/
- private def enumScaffolding(implicit ctx: Context): List[Tree] = {
- def valuesDot(name: String) = Select(Ident(nme.DOLLAR_VALUES), name.toTermName)
- def enumDefDef(name: String, select: String) =
- DefDef(name.toTermName, Nil, Nil, TypeTree(), valuesDot(select))
+ private def enumValueCreator(implicit ctx: Context) = {
def param(name: TermName, typ: Type) =
ValDef(name, TypeTree(typ), EmptyTree).withFlags(Param)
- val privateValuesDef =
- ValDef(nme.DOLLAR_VALUES, TypeTree(),
- New(TypeTree(defn.EnumValuesType.appliedTo(enumClass.typeRef :: Nil)), ListOfNil))
- .withFlags(Private)
- val valueOfDef = enumDefDef("valueOf", "fromInt")
- val withNameDef = enumDefDef("withName", "fromName")
- val valuesDef = enumDefDef("values", "values")
val enumTagDef =
DefDef(nme.enumTag, Nil, Nil, TypeTree(), Ident(nme.tag))
val toStringDef =
DefDef(nme.toString_, Nil, Nil, TypeTree(), Ident(nme.name))
.withFlags(Override)
- val registerStat =
- Apply(valuesDot("register"), This(EmptyTypeIdent) :: Nil)
def creator = New(Template(emptyConstructor, enumClassRef :: Nil, EmptyValDef,
- List(enumTagDef, toStringDef, registerStat)))
- val newDef =
- DefDef(nme.DOLLAR_NEW, Nil,
- List(List(param(nme.tag, defn.IntType), param(nme.name, defn.StringType))),
- TypeTree(), creator)
- List(privateValuesDef, valueOfDef, withNameDef, valuesDef, newDef)
+ List(enumTagDef, toStringDef, registerCall)))
+ DefDef(nme.DOLLAR_NEW, Nil,
+ List(List(param(nme.tag, defn.IntType), param(nme.name, defn.StringType))),
+ TypeTree(), creator)
+ }
+
+ /** A pair consisting of
+ * - the next enum tag
+ * - scaffolding containing the necessary definitions for singleton enum cases
+ * unless that scaffolding was already generated by a previous call to `nextEnumKind`.
+ */
+ def nextEnumTag(kind: CaseKind.Value)(implicit ctx: Context): (Int, List[Tree]) = {
+ val (count, seenKind) = ctx.tree.removeAttachment(EnumCaseCount).getOrElse((0, CaseKind.Class))
+ val minKind = if (kind < seenKind) kind else seenKind
+ ctx.tree.pushAttachment(EnumCaseCount, (count + 1, minKind))
+ val scaffolding =
+ if (kind >= seenKind) Nil
+ else if (kind == CaseKind.Object) enumScaffolding
+ else if (seenKind == CaseKind.Object) enumValueCreator :: Nil
+ else enumScaffolding :+ enumValueCreator
+ (count, scaffolding)
+ }
+
+ /** A pair consisting of
+ * - a method returning the next enum tag
+ * - scaffolding as defined in `nextEnumTag`
+ */
+ def enumTagMeth(kind: CaseKind.Value)(implicit ctx: Context): (DefDef, List[Tree]) = {
+ val (tag, scaffolding) = nextEnumTag(kind)
+ (DefDef(nme.enumTag, Nil, Nil, TypeTree(), Literal(Constant(tag))), scaffolding)
}
+ /** Expand a module definition representing a parameterless enum case */
def expandEnumModule(name: TermName, impl: Template, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree =
if (impl.parents.isEmpty)
if (impl.body.isEmpty)
@@ -146,22 +176,23 @@ object DesugarEnums {
def toStringMeth =
DefDef(nme.toString_, Nil, Nil, TypeTree(defn.StringType), Literal(Constant(name.toString)))
.withFlags(Override)
- val impl1 = cpy.Template(impl)(body =
- impl.body ++ List(enumTagMeth, toStringMeth))
- ValDef(name, TypeTree(), New(impl1)).withMods(mods | Final).withPos(pos)
+ val (tagMeth, scaffolding) = enumTagMeth(CaseKind.Object)
+ val impl1 = cpy.Template(impl)(body = impl.body ++ List(tagMeth, toStringMeth, registerCall))
+ val vdef = ValDef(name, TypeTree(), New(impl1)).withMods(mods | Final).withPos(pos)
+ flatTree(scaffolding ::: vdef :: Nil).withPos(pos.startPos)
}
+ /** Expand a simple enum case */
def expandSimpleEnumCase(name: TermName, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree =
- if (reconstitutedEnumTypeParams(pos).nonEmpty) {
+ if (enumClass.typeParams.nonEmpty) {
val parent = interpolatedEnumParent(pos)
val impl = Template(emptyConstructor, parent :: Nil, EmptyValDef, Nil)
expandEnumModule(name, impl, mods, pos)
}
else {
- val (tag, simpleSeen) = nextEnumTag(isSimpleCase = true)
- val prefix = if (simpleSeen) Nil else enumScaffolding
+ val (tag, scaffolding) = nextEnumTag(CaseKind.Simple)
val creator = Apply(Ident(nme.DOLLAR_NEW), List(Literal(Constant(tag)), Literal(Constant(name.toString))))
val vdef = ValDef(name, enumClassRef, creator).withMods(mods | Final).withPos(pos)
- flatTree(prefix ::: vdef :: Nil).withPos(pos.startPos)
+ flatTree(scaffolding ::: vdef :: Nil).withPos(pos.startPos)
}
}