aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2017-02-28 18:59:08 +0100
committerMartin Odersky <odersky@gmail.com>2017-04-04 13:29:38 +0200
commit44d9ab81886a9ff0b7256fccb584c049f1c18027 (patch)
treeeff314cd55d1917ed9f1cb1d6caba551a3f04a51
parent91a26b3f42d1218015acb9b7e1bfc180e3ed779b (diff)
downloaddotty-44d9ab81886a9ff0b7256fccb584c049f1c18027.tar.gz
dotty-44d9ab81886a9ff0b7256fccb584c049f1c18027.tar.bz2
dotty-44d9ab81886a9ff0b7256fccb584c049f1c18027.zip
Support cases with type parameters that extend a non-parameterized base
Support cases with type parameters that implicitly extend a non-parameterized base without needing their own extends clause. The proposal has been updated to make clear that this is supported. Also address other reviewers comments.
-rw-r--r--compiler/src/dotty/tools/dotc/ast/Desugar.scala20
-rw-r--r--compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala20
-rw-r--r--tests/run/enum-HList.scala22
3 files changed, 46 insertions, 16 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
index 04834b04b..80da75678 100644
--- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
@@ -296,11 +296,16 @@ object desugar {
val isValueClass = parents.nonEmpty && isAnyVal(parents.head)
// This is not watertight, but `extends AnyVal` will be replaced by `inline` later.
+ lazy val reconstitutedTypeParams = reconstitutedEnumTypeParams(cdef.pos.startPos)
+
val originalTparams =
if (isEnumCase && parents.isEmpty) {
- if (constr1.tparams.nonEmpty)
- ctx.error(em"case with type parameters needs extends clause", constr1.tparams.head.pos)
- reconstitutedEnumTypeParams(cdef.pos.startPos)
+ if (constr1.tparams.nonEmpty) {
+ if (reconstitutedTypeParams.nonEmpty)
+ ctx.error(em"case with type parameters needs extends clause", constr1.tparams.head.pos)
+ constr1.tparams
+ }
+ else reconstitutedTypeParams
}
else constr1.tparams
val originalVparamss = constr1.vparamss
@@ -339,7 +344,9 @@ object desugar {
// a reference to the class type bound by `cdef`, with type parameters coming from the constructor
val classTypeRef = appliedRef(classTycon)
// a reference to `enumClass`, with type parameters coming from the constructor
- lazy val enumClassTypeRef = appliedRef(enumClassRef)
+ lazy val enumClassTypeRef =
+ if (reconstitutedTypeParams.isEmpty) enumClassRef
+ else appliedRef(enumClassRef)
// new C[Ts](paramss)
lazy val creatorExpr = New(classTypeRef, constrVparamss nestedMap refOfDef)
@@ -516,10 +523,7 @@ object desugar {
case _ =>
}
- val result = flatTree(cdef1 :: companions ::: implicitWrappers)
- //if (isEnum) println(i"enum $cdef\n --->\n$result")
- //if (isEnumCase) println(i"enum case $cdef\n --->\n$result")
- result
+ flatTree(cdef1 :: companions ::: implicitWrappers)
}
val AccessOrSynthetic = AccessFlags | Synthetic
diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala
index 7fdff0e2d..c5c95d647 100644
--- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala
+++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala
@@ -14,14 +14,17 @@ object DesugarEnums {
import untpd._
import desugar.DerivedFromParamTree
- val EnumCaseCount = new Property.Key[Int]
+ /** 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)]
def enumClass(implicit ctx: Context) = ctx.owner.linkedClass
- def nextEnumTag(implicit ctx: Context): Int = {
- val result = ctx.tree.removeAttachment(EnumCaseCount).getOrElse(0)
- ctx.tree.pushAttachment(EnumCaseCount, result + 1)
- result
+ 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)
}
def isLegalEnumCase(tree: MemberDef)(implicit ctx: Context): Boolean =
@@ -54,7 +57,8 @@ object DesugarEnums {
}
def enumTagMeth(implicit ctx: Context) =
- DefDef(nme.enumTag, Nil, Nil, TypeTree(), Literal(Constant(nextEnumTag)))
+ DefDef(nme.enumTag, Nil, Nil, TypeTree(),
+ Literal(Constant(nextEnumTag(isSimpleCase = false)._1)))
def enumClassRef(implicit ctx: Context) = TypeTree(enumClass.typeRef)
@@ -120,8 +124,8 @@ object DesugarEnums {
def expandSimpleEnumCase(name: TermName, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree = {
if (reconstitutedEnumTypeParams(pos).nonEmpty)
ctx.error(i"illegal enum value of generic $enumClass: an explicit `extends' clause is needed", pos)
- val tag = nextEnumTag
- val prefix = if (tag == 0) enumScaffolding else Nil
+ val (tag, simpleSeen) = nextEnumTag(isSimpleCase = true)
+ val prefix = if (simpleSeen) Nil else enumScaffolding
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)
diff --git a/tests/run/enum-HList.scala b/tests/run/enum-HList.scala
new file mode 100644
index 000000000..c019cb6cc
--- /dev/null
+++ b/tests/run/enum-HList.scala
@@ -0,0 +1,22 @@
+enum HLst {
+ case HCons[+Hd, +Tl <: HLst](hd: Hd, tl: Tl)
+ case HNil
+}
+
+object Test {
+ import HLst._
+ def length(hl: HLst): Int = hl match {
+ case HCons(_, tl) => 1 + length(tl)
+ case HNil => 0
+ }
+ def sumInts(hl: HLst): Int = hl match {
+ case HCons(x: Int, tl) => x + sumInts(tl)
+ case HCons(_, tl) => sumInts(tl)
+ case HNil => 0
+ }
+ def main(args: Array[String]) = {
+ val hl = HCons(1, HCons("A", HNil))
+ assert(length(hl) == 2, length(hl))
+ assert(sumInts(hl) == 1)
+ }
+}