aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2017-04-04 18:31:52 +0200
committerMartin Odersky <odersky@gmail.com>2017-04-04 18:31:52 +0200
commita46f4f840a456bb70ef4b95e6b18608522075442 (patch)
tree5a03fc0160085ccc87a8bdf75064af2f05eb023a
parent1c79612c57af81acec2480bef56240dcf5ec30d1 (diff)
downloaddotty-a46f4f840a456bb70ef4b95e6b18608522075442.tar.gz
dotty-a46f4f840a456bb70ef4b95e6b18608522075442.tar.bz2
dotty-a46f4f840a456bb70ef4b95e6b18608522075442.zip
Infer enum type args from type parameter bounds
Infer type arguments for enum paraments from corresponding type parameter bounds. This only works if the type parameter in question is variant and its bound is ground.
-rw-r--r--compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala56
-rw-r--r--tests/neg/enums.scala13
2 files changed, 57 insertions, 12 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala
index c5c95d647..ae4ba23d5 100644
--- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala
+++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala
@@ -8,7 +8,7 @@ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._
import Decorators._
import collection.mutable.ListBuffer
import util.Property
-import reporting.diagnostic.messages._
+import typer.ErrorReporting._
object DesugarEnums {
import untpd._
@@ -56,6 +56,31 @@ object DesugarEnums {
}
}
+ /** A reference to the enum class `E`, possibly followed by type arguments.
+ * Each covariant type parameter is approximated by its lower bound.
+ * Each contravariant type parameter is approximated by its upper bound.
+ * It is an error if a type parameter is non-variant, or if its approximation
+ * refers to pther type parameters.
+ */
+ def interpolatedEnumParent(pos: Position)(implicit ctx: Context): Tree = {
+ val tparams = enumClass.typeParams
+ def isGround(tp: Type) = tp.subst(tparams, tparams.map(_ => NoType)) eq tp
+ val targs = tparams map { tparam =>
+ if (tparam.variance > 0 && isGround(tparam.info.bounds.lo))
+ tparam.info.bounds.lo
+ else if (tparam.variance < 0 && isGround(tparam.info.bounds.hi))
+ tparam.info.bounds.hi
+ else {
+ def problem =
+ if (tparam.variance == 0) "is non variant"
+ else "has bounds that depend on a type parameter in the same parameter list"
+ errorType(i"""cannot determine type argument for enum parent $enumClass,
+ |type parameter $tparam $problem""", pos)
+ }
+ }
+ TypeTree(enumClass.typeRef.appliedTo(targs)).withPos(pos)
+ }
+
def enumTagMeth(implicit ctx: Context) =
DefDef(nme.enumTag, Nil, Nil, TypeTree(),
Literal(Constant(nextEnumTag(isSimpleCase = false)._1)))
@@ -111,7 +136,12 @@ object DesugarEnums {
def expandEnumModule(name: TermName, impl: Template, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree =
if (impl.parents.isEmpty)
- expandSimpleEnumCase(name, mods, pos)
+ if (impl.body.isEmpty)
+ expandSimpleEnumCase(name, mods, pos)
+ else {
+ val parent = interpolatedEnumParent(pos)
+ expandEnumModule(name, cpy.Template(impl)(parents = parent :: Nil), mods, pos)
+ }
else {
def toStringMeth =
DefDef(nme.toString_, Nil, Nil, TypeTree(defn.StringType), Literal(Constant(name.toString)))
@@ -121,13 +151,17 @@ object DesugarEnums {
ValDef(name, TypeTree(), New(impl1)).withMods(mods | Final).withPos(pos)
}
- 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, 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)
- }
+ def expandSimpleEnumCase(name: TermName, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree =
+ if (reconstitutedEnumTypeParams(pos).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 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/neg/enums.scala b/tests/neg/enums.scala
index d6f75e2b9..1ed3007e7 100644
--- a/tests/neg/enums.scala
+++ b/tests/neg/enums.scala
@@ -1,9 +1,20 @@
enum List[+T] {
case Cons(x: T, xs: List[T])
- case Nil // error: illegal enum value
case Snoc[U](xs: List[U], x: U) // error: case with type parameters needs extends clause
}
enum class X {
case Y // error: case not allowed here
}
+
+enum E1[T] {
+ case C
+}
+
+enum E2[+T, +U >: T] {
+ case C
+}
+
+enum E3[-T <: Ordered[T]] {
+ case C
+}