Skip to content

Commit 5efbe52

Browse files
authored
Merge pull request #2460 from dotty-staging/change-enum
Change enum scheme to correspond to new description in issue #1970
2 parents 34b98f3 + 1ed4e0d commit 5efbe52

File tree

12 files changed

+37
-55
lines changed

12 files changed

+37
-55
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -296,18 +296,8 @@ object desugar {
296296
val isValueClass = parents.nonEmpty && isAnyVal(parents.head)
297297
// This is not watertight, but `extends AnyVal` will be replaced by `inline` later.
298298

299-
lazy val reconstitutedTypeParams = reconstitutedEnumTypeParams(cdef.pos.startPos)
300-
301-
val originalTparams =
302-
if (isEnumCase && parents.isEmpty) {
303-
if (constr1.tparams.nonEmpty) {
304-
if (reconstitutedTypeParams.nonEmpty)
305-
ctx.error(em"case with type parameters needs extends clause", constr1.tparams.head.pos)
306-
constr1.tparams
307-
}
308-
else reconstitutedTypeParams
309-
}
310-
else constr1.tparams
299+
300+
val originalTparams = constr1.tparams
311301
val originalVparamss = constr1.vparamss
312302
val constrTparams = originalTparams.map(toDefParam)
313303
val constrVparamss =
@@ -328,9 +318,9 @@ object desugar {
328318
case stat =>
329319
stat
330320
}
321+
def anyRef = ref(defn.AnyRefAlias.typeRef)
331322

332-
val derivedTparams =
333-
if (isEnumCase) constrTparams else constrTparams map derivedTypeParam
323+
val derivedTparams = constrTparams map derivedTypeParam
334324
val derivedVparamss = constrVparamss nestedMap derivedTermParam
335325
val arity = constrVparamss.head.length
336326

@@ -343,10 +333,23 @@ object desugar {
343333

344334
// a reference to the class type bound by `cdef`, with type parameters coming from the constructor
345335
val classTypeRef = appliedRef(classTycon)
346-
// a reference to `enumClass`, with type parameters coming from the constructor
347-
lazy val enumClassTypeRef =
348-
if (reconstitutedTypeParams.isEmpty) enumClassRef
349-
else appliedRef(enumClassRef)
336+
337+
// a reference to `enumClass`, with type parameters coming from the case constructor
338+
lazy val enumClassTypeRef = enumClass.primaryConstructor.info match {
339+
case info: PolyType =>
340+
if (constrTparams.isEmpty)
341+
interpolatedEnumParent(cdef.pos.startPos)
342+
else if ((constrTparams.corresponds(info.paramNames))((param, name) => param.name == name))
343+
appliedRef(enumClassRef)
344+
else {
345+
ctx.error(i"explicit extends clause needed because type parameters of case and enum class differ"
346+
, cdef.pos.startPos)
347+
AppliedTypeTree(enumClassRef, constrTparams map (_ => anyRef))
348+
.withPos(cdef.pos.startPos)
349+
}
350+
case _ =>
351+
enumClassRef
352+
}
350353

351354
// new C[Ts](paramss)
352355
lazy val creatorExpr = New(classTypeRef, constrVparamss nestedMap refOfDef)
@@ -399,8 +402,6 @@ object desugar {
399402
else Nil
400403
}
401404

402-
def anyRef = ref(defn.AnyRefAlias.typeRef)
403-
404405
// Case classes and case objects get Product parents
405406
var parents1 = parents
406407
if (isEnumCase && parents.isEmpty)

compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -37,25 +37,6 @@ object DesugarEnums {
3737
}
3838
)
3939

40-
/** Type parameters reconstituted from the constructor
41-
* of the `enum' class corresponding to an enum case.
42-
* The variance is the same as the corresponding type parameter of the enum class.
43-
*/
44-
def reconstitutedEnumTypeParams(pos: Position)(implicit ctx: Context) = {
45-
val tparams = enumClass.primaryConstructor.info match {
46-
case info: PolyType =>
47-
ctx.newTypeParams(ctx.newLocalDummy(enumClass), info.paramNames, EmptyFlags, info.instantiateBounds)
48-
case _ =>
49-
Nil
50-
}
51-
(tparams, enumClass.typeParams).zipped.map { (tparam, ecTparam) =>
52-
val tbounds = new DerivedFromParamTree
53-
tbounds.pushAttachment(OriginalSymbol, tparam)
54-
TypeDef(tparam.name, tbounds)
55-
.withFlags(Param | PrivateLocal | ecTparam.flags & VarianceFlags).withPos(pos)
56-
}
57-
}
58-
5940
/** A reference to the enum class `E`, possibly followed by type arguments.
6041
* Each covariant type parameter is approximated by its lower bound.
6142
* Each contravariant type parameter is approximated by its upper bound.

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,13 +1144,12 @@ object Parsers {
11441144
val name = bindingName()
11451145
val t =
11461146
if (in.token == COLON && location == Location.InBlock) {
1147-
if (false) // Don't error yet, as the alternative syntax "implicit (x: T) => ... "
1148-
// is not supported by Scala2.x
1147+
if (ctx.settings.strict.value)
1148+
// Don't error in non-strict mode, as the alternative syntax "implicit (x: T) => ... "
1149+
// is not supported by Scala2.x
11491150
migrationWarningOrError(s"This syntax is no longer supported; parameter needs to be enclosed in (...)")
1150-
11511151
in.nextToken()
11521152
val t = infixType()
1153-
11541153
if (false && in.isScala2Mode) {
11551154
patch(source, Position(start), "(")
11561155
patch(source, Position(in.lastOffset), ")")

compiler/test/dotc/tests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ class tests extends CompilerTest {
105105
val libDir = "../library/src/"
106106

107107
def dottyBootedLib = compileDir(libDir, ".", List("-deep", "-Ycheck-reentrant", "-strict") ::: defaultOptions)(allowDeepSubtypes) // note the -deep argument
108-
def dottyDependsOnBootedLib = compileDir(dottyDir, ".", List("-deep", "-Ycheck-reentrant", "-strict") ::: defaultOptions)(allowDeepSubtypes) // note the -deep argument
108+
def dottyDependsOnBootedLib = compileDir(dottyDir, ".", List("-deep", "-Ycheck-reentrant") ::: defaultOptions)(allowDeepSubtypes) // note the -deep argument
109109

110110
@Before def cleanup(): Unit = {
111111
// remove class files from stdlib and tests compilation

tests/neg/enums.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
enum List[+T] {
2-
case Cons(x: T, xs: List[T])
3-
case Snoc[U](xs: List[U], x: U) // error: case with type parameters needs extends clause
2+
case Cons[T](x: T, xs: List[T]) // ok
3+
case Snoc[U](xs: List[U], x: U) // error: different type parameters
44
}
55

66
enum class X {

tests/patmat/enum-Tree.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ enum Tree[T] {
55
case Succ(n: Tree[Int]) extends Tree[Int]
66
case Pred(n: Tree[Int]) extends Tree[Int]
77
case IsZero(n: Tree[Int]) extends Tree[Boolean]
8-
case If(cond: Tree[Boolean], thenp: Tree[T], elsep: Tree[T])
8+
case If[T](cond: Tree[Boolean], thenp: Tree[T], elsep: Tree[T])
99
}
1010

1111
object Test {

tests/run/enum-List1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
enum class List[T]
22
object List {
3-
case Cons(x: T, xs: List[T])
4-
case Nil()
3+
case Cons[T](x: T, xs: List[T])
4+
case Nil[T]()
55
}
66
object Test {
77
import List._

tests/run/enum-List2.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
enum class List[+T]
22
object List {
3-
case Cons(x: T, xs: List[T])
3+
case Cons[+T](x: T, xs: List[T])
44
case Nil extends List[Nothing]
55
}
66
object Test {

tests/run/enum-List2a.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
enum class List[+T]
22
object List {
3-
case Cons(x: T, xs: List[T])
3+
case Cons[+T](x: T, xs: List[T])
44
case Nil
55
}
66
object Test {

tests/run/enum-List3.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
enum List[+T] {
2-
case Cons(x: T, xs: List[T])
3-
case Nil extends List[Nothing]
2+
case Cons[T](x: T, xs: List[T])
3+
case Nil
44
}
55
object Test {
66
import List._

tests/run/enum-Option.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ enum class Option[+T >: Null] extends Serializable {
33
}
44
object Option {
55
def apply[T >: Null](x: T): Option[T] = if (x == null) None else Some(x)
6-
case Some(x: T) {
6+
7+
case Some[+T >: Null](x: T) {
78
def isDefined = true
89
}
910
case None {

tests/run/enum-Tree.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ enum Tree[T] {
55
case Succ(n: Tree[Int]) extends Tree[Int]
66
case Pred(n: Tree[Int]) extends Tree[Int]
77
case IsZero(n: Tree[Int]) extends Tree[Boolean]
8-
case If(cond: Tree[Boolean], thenp: Tree[T], elsep: Tree[T])
8+
case If[T](cond: Tree[Boolean], thenp: Tree[T], elsep: Tree[T])
99
}
1010

1111
object Test {

0 commit comments

Comments
 (0)