diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index c2d24608c72e..ff132944f0e4 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -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 = @@ -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 @@ -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) @@ -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) diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala index 43f915961d8f..ba896b307473 100644 --- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala +++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala @@ -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. diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index d5e37be8676c..80f0f9747917 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -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), ")") diff --git a/compiler/test/dotc/tests.scala b/compiler/test/dotc/tests.scala index cb6bc394db1e..ee441d44b4bd 100644 --- a/compiler/test/dotc/tests.scala +++ b/compiler/test/dotc/tests.scala @@ -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 diff --git a/tests/neg/enums.scala b/tests/neg/enums.scala index 108ec4a6cbfb..d48d90078f96 100644 --- a/tests/neg/enums.scala +++ b/tests/neg/enums.scala @@ -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 { diff --git a/tests/patmat/enum-Tree.scala b/tests/patmat/enum-Tree.scala index ef5bd7a5714e..68e4fc012545 100644 --- a/tests/patmat/enum-Tree.scala +++ b/tests/patmat/enum-Tree.scala @@ -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 { diff --git a/tests/run/enum-List1.scala b/tests/run/enum-List1.scala index bb75bec4a1ec..03a81bd991bd 100644 --- a/tests/run/enum-List1.scala +++ b/tests/run/enum-List1.scala @@ -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._ diff --git a/tests/run/enum-List2.scala b/tests/run/enum-List2.scala index 030de0f849aa..6a1d8d894b78 100644 --- a/tests/run/enum-List2.scala +++ b/tests/run/enum-List2.scala @@ -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 { diff --git a/tests/run/enum-List2a.scala b/tests/run/enum-List2a.scala index 323a5587c1a3..d4f47c2da4ef 100644 --- a/tests/run/enum-List2a.scala +++ b/tests/run/enum-List2a.scala @@ -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 { diff --git a/tests/run/enum-List3.scala b/tests/run/enum-List3.scala index e5ffe1a28ce1..8275e8bc3264 100644 --- a/tests/run/enum-List3.scala +++ b/tests/run/enum-List3.scala @@ -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._ diff --git a/tests/run/enum-Option.scala b/tests/run/enum-Option.scala index 76f5641b3418..6bdb2b1eb262 100644 --- a/tests/run/enum-Option.scala +++ b/tests/run/enum-Option.scala @@ -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 { diff --git a/tests/run/enum-Tree.scala b/tests/run/enum-Tree.scala index ef5bd7a5714e..68e4fc012545 100644 --- a/tests/run/enum-Tree.scala +++ b/tests/run/enum-Tree.scala @@ -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 {