Skip to content

Change enum scheme to correspond to new description in issue #1970 #2460

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 21 additions & 20 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -296,18 +296,8 @@ 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) {
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 originalTparams = constr1.tparams
val originalVparamss = constr1.vparamss
val constrTparams = originalTparams.map(toDefParam)
val constrVparamss =
Expand All @@ -328,9 +318,9 @@ object desugar {
case stat =>
stat
}
def anyRef = ref(defn.AnyRefAlias.typeRef)

val derivedTparams =
if (isEnumCase) constrTparams else constrTparams map derivedTypeParam
val derivedTparams = constrTparams map derivedTypeParam
val derivedVparamss = constrVparamss nestedMap derivedTermParam
val arity = constrVparamss.head.length

Expand All @@ -343,10 +333,23 @@ 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 =
if (reconstitutedTypeParams.isEmpty) enumClassRef
else appliedRef(enumClassRef)

// a reference to `enumClass`, with type parameters coming from the case constructor
lazy val enumClassTypeRef = enumClass.primaryConstructor.info match {
case info: PolyType =>
if (constrTparams.isEmpty)
interpolatedEnumParent(cdef.pos.startPos)
else if ((constrTparams.corresponds(info.paramNames))((param, name) => param.name == name))
appliedRef(enumClassRef)
else {
ctx.error(i"explicit extends clause needed because type parameters of case and enum class differ"
, cdef.pos.startPos)
AppliedTypeTree(enumClassRef, constrTparams map (_ => anyRef))
.withPos(cdef.pos.startPos)
}
case _ =>
enumClassRef
}

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

def anyRef = ref(defn.AnyRefAlias.typeRef)

// Case classes and case objects get Product parents
var parents1 = parents
if (isEnumCase && parents.isEmpty)
Expand Down
19 changes: 0 additions & 19 deletions compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,6 @@ object DesugarEnums {
}
)

/** Type parameters reconstituted from the constructor
* of the `enum' class corresponding to an enum case.
* The variance is the same as the corresponding type parameter of the enum class.
*/
def reconstitutedEnumTypeParams(pos: Position)(implicit ctx: Context) = {
val tparams = enumClass.primaryConstructor.info match {
case info: PolyType =>
ctx.newTypeParams(ctx.newLocalDummy(enumClass), info.paramNames, EmptyFlags, info.instantiateBounds)
case _ =>
Nil
}
(tparams, enumClass.typeParams).zipped.map { (tparam, ecTparam) =>
val tbounds = new DerivedFromParamTree
tbounds.pushAttachment(OriginalSymbol, tparam)
TypeDef(tparam.name, tbounds)
.withFlags(Param | PrivateLocal | ecTparam.flags & VarianceFlags).withPos(pos)
}
}

/** 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.
Expand Down
7 changes: 3 additions & 4 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1144,13 +1144,12 @@ object Parsers {
val name = bindingName()
val t =
if (in.token == COLON && location == Location.InBlock) {
if (false) // Don't error yet, as the alternative syntax "implicit (x: T) => ... "
// is not supported by Scala2.x
if (ctx.settings.strict.value)
// Don't error in non-strict mode, as the alternative syntax "implicit (x: T) => ... "
// is not supported by Scala2.x
migrationWarningOrError(s"This syntax is no longer supported; parameter needs to be enclosed in (...)")

in.nextToken()
val t = infixType()

if (false && in.isScala2Mode) {
patch(source, Position(start), "(")
patch(source, Position(in.lastOffset), ")")
Expand Down
2 changes: 1 addition & 1 deletion compiler/test/dotc/tests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class tests extends CompilerTest {
val libDir = "../library/src/"

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

@Before def cleanup(): Unit = {
// remove class files from stdlib and tests compilation
Expand Down
4 changes: 2 additions & 2 deletions tests/neg/enums.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
enum List[+T] {
case Cons(x: T, xs: List[T])
case Snoc[U](xs: List[U], x: U) // error: case with type parameters needs extends clause
case Cons[T](x: T, xs: List[T]) // ok
case Snoc[U](xs: List[U], x: U) // error: different type parameters
}

enum class X {
Expand Down
2 changes: 1 addition & 1 deletion tests/patmat/enum-Tree.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ enum Tree[T] {
case Succ(n: Tree[Int]) extends Tree[Int]
case Pred(n: Tree[Int]) extends Tree[Int]
case IsZero(n: Tree[Int]) extends Tree[Boolean]
case If(cond: Tree[Boolean], thenp: Tree[T], elsep: Tree[T])
case If[T](cond: Tree[Boolean], thenp: Tree[T], elsep: Tree[T])
}

object Test {
Expand Down
4 changes: 2 additions & 2 deletions tests/run/enum-List1.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
enum class List[T]
object List {
case Cons(x: T, xs: List[T])
case Nil()
case Cons[T](x: T, xs: List[T])
case Nil[T]()
}
object Test {
import List._
Expand Down
2 changes: 1 addition & 1 deletion tests/run/enum-List2.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
enum class List[+T]
object List {
case Cons(x: T, xs: List[T])
case Cons[+T](x: T, xs: List[T])
case Nil extends List[Nothing]
}
object Test {
Expand Down
2 changes: 1 addition & 1 deletion tests/run/enum-List2a.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
enum class List[+T]
object List {
case Cons(x: T, xs: List[T])
case Cons[+T](x: T, xs: List[T])
case Nil
}
object Test {
Expand Down
4 changes: 2 additions & 2 deletions tests/run/enum-List3.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
enum List[+T] {
case Cons(x: T, xs: List[T])
case Nil extends List[Nothing]
case Cons[T](x: T, xs: List[T])
case Nil
}
object Test {
import List._
Expand Down
3 changes: 2 additions & 1 deletion tests/run/enum-Option.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ enum class Option[+T >: Null] extends Serializable {
}
object Option {
def apply[T >: Null](x: T): Option[T] = if (x == null) None else Some(x)
case Some(x: T) {

case Some[+T >: Null](x: T) {
def isDefined = true
}
case None {
Expand Down
2 changes: 1 addition & 1 deletion tests/run/enum-Tree.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ enum Tree[T] {
case Succ(n: Tree[Int]) extends Tree[Int]
case Pred(n: Tree[Int]) extends Tree[Int]
case IsZero(n: Tree[Int]) extends Tree[Boolean]
case If(cond: Tree[Boolean], thenp: Tree[T], elsep: Tree[T])
case If[T](cond: Tree[Boolean], thenp: Tree[T], elsep: Tree[T])
}

object Test {
Expand Down