From 6891d2f2a604ad909687b0a95906ca8ccbc14dc9 Mon Sep 17 00:00:00 2001 From: Sebastian Nadorp Date: Tue, 15 May 2018 12:10:00 +0200 Subject: [PATCH 01/10] Fix #4470: compiler crash for repeated Enums --- compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala | 3 ++- tests/neg/enum-repeated-4470.scala | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 tests/neg/enum-repeated-4470.scala diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala index e6e48f75ede5..c10456b94527 100644 --- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala +++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala @@ -210,7 +210,8 @@ object DesugarEnums { /** Expand a simple enum case */ def expandSimpleEnumCase(name: TermName, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree = - if (enumClass.typeParams.nonEmpty) { + if (!enumClass.exists) EmptyTree + else if (enumClass.typeParams.nonEmpty) { val parent = interpolatedEnumParent(pos) val impl = Template(emptyConstructor, parent :: Nil, EmptyValDef, Nil) expandEnumModule(name, impl, mods, pos) diff --git a/tests/neg/enum-repeated-4470.scala b/tests/neg/enum-repeated-4470.scala new file mode 100644 index 000000000000..d06ca57a01ad --- /dev/null +++ b/tests/neg/enum-repeated-4470.scala @@ -0,0 +1,10 @@ +object RepeatedEnum { + + enum Maybe { //error + case Foo + } + + enum Maybe { //error + case Foo + } +} From e2a6cafc3f6c2d92c38aa6ba7b5450cf25b28aa7 Mon Sep 17 00:00:00 2001 From: Sebastian Nadorp Date: Tue, 15 May 2018 13:11:39 +0200 Subject: [PATCH 02/10] Fix testcase. --- tests/neg/enum-repeated-4470.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/neg/enum-repeated-4470.scala b/tests/neg/enum-repeated-4470.scala index d06ca57a01ad..b0c4b2c3d405 100644 --- a/tests/neg/enum-repeated-4470.scala +++ b/tests/neg/enum-repeated-4470.scala @@ -1,10 +1,10 @@ object RepeatedEnum { - enum Maybe { //error + enum Maybe { // error // error case Foo } - enum Maybe { //error + enum Maybe { // error case Foo } } From fdd5f6c3c8e663569c37511c51bce8bb9d48d46b Mon Sep 17 00:00:00 2001 From: Sebastian Nadorp Date: Tue, 15 May 2018 14:08:58 +0200 Subject: [PATCH 03/10] Fix compiler crash for already compiled classes --- .../dotty/tools/dotc/ast/DesugarEnums.scala | 19 +++++++++++-------- tests/neg/enum-repeated-extend-4470.scala | 10 ++++++++++ 2 files changed, 21 insertions(+), 8 deletions(-) create mode 100644 tests/neg/enum-repeated-extend-4470.scala diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala index c10456b94527..65c96d339361 100644 --- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala +++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala @@ -87,14 +87,17 @@ object DesugarEnums { private def enumScaffolding(implicit ctx: Context): List[Tree] = { def enumDefDef(name: String, select: String) = DefDef(name.toTermName, Nil, Nil, TypeTree(), valuesDot(select)) - val privateValuesDef = - ValDef(nme.DOLLAR_VALUES, TypeTree(), - New(TypeTree(defn.EnumValuesType.appliedTo(enumClass.typeRef :: Nil)), ListOfNil)) - .withFlags(Private) - val valueOfDef = enumDefDef("enumValue", "fromInt") - val withNameDef = enumDefDef("enumValueNamed", "fromName") - val valuesDef = enumDefDef("enumValues", "values") - List(privateValuesDef, valueOfDef, withNameDef, valuesDef) + + if (enumClass.exists) { + val privateValuesDef = + ValDef(nme.DOLLAR_VALUES, TypeTree(), + New(TypeTree(defn.EnumValuesType.appliedTo(enumClass.typeRef :: Nil)), ListOfNil)) + .withFlags(Private) + val valueOfDef = enumDefDef("enumValue", "fromInt") + val withNameDef = enumDefDef("enumValueNamed", "fromName") + val valuesDef = enumDefDef("enumValues", "values") + List(privateValuesDef, valueOfDef, withNameDef, valuesDef) + } else List.empty } /** A creation method for a value of enum type `E`, which is defined as follows: diff --git a/tests/neg/enum-repeated-extend-4470.scala b/tests/neg/enum-repeated-extend-4470.scala new file mode 100644 index 000000000000..d248bb027954 --- /dev/null +++ b/tests/neg/enum-repeated-extend-4470.scala @@ -0,0 +1,10 @@ +object RepeatedExtendEnum { + + enum Maybe[T] { + case Foo extends Maybe[Int] + } + + enum Maybe[T] { + case Foo extends Maybe[Int] + } +} From 4f36b2bf511c2502e429d9d340a4c5544d1f7155 Mon Sep 17 00:00:00 2001 From: Sebastian Nadorp Date: Tue, 15 May 2018 14:12:56 +0200 Subject: [PATCH 04/10] Add error assertions --- tests/neg/enum-repeated-extend-4470.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/neg/enum-repeated-extend-4470.scala b/tests/neg/enum-repeated-extend-4470.scala index d248bb027954..716f3edc1089 100644 --- a/tests/neg/enum-repeated-extend-4470.scala +++ b/tests/neg/enum-repeated-extend-4470.scala @@ -1,10 +1,10 @@ object RepeatedExtendEnum { - enum Maybe[T] { + enum Maybe[T] { // error // error case Foo extends Maybe[Int] } - enum Maybe[T] { + enum Maybe[T] { // error case Foo extends Maybe[Int] } } From 36e722e0bb7aaa3d61fb4614634688162fb01326 Mon Sep 17 00:00:00 2001 From: Sebastian Nadorp Date: Tue, 15 May 2018 14:24:21 +0200 Subject: [PATCH 05/10] Remove duplicated check. --- .../dotty/tools/dotc/ast/DesugarEnums.scala | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala index 65c96d339361..3bcb2ab8d344 100644 --- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala +++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala @@ -88,16 +88,14 @@ object DesugarEnums { def enumDefDef(name: String, select: String) = DefDef(name.toTermName, Nil, Nil, TypeTree(), valuesDot(select)) - if (enumClass.exists) { - val privateValuesDef = - ValDef(nme.DOLLAR_VALUES, TypeTree(), - New(TypeTree(defn.EnumValuesType.appliedTo(enumClass.typeRef :: Nil)), ListOfNil)) - .withFlags(Private) - val valueOfDef = enumDefDef("enumValue", "fromInt") - val withNameDef = enumDefDef("enumValueNamed", "fromName") - val valuesDef = enumDefDef("enumValues", "values") - List(privateValuesDef, valueOfDef, withNameDef, valuesDef) - } else List.empty + val privateValuesDef = + ValDef(nme.DOLLAR_VALUES, TypeTree(), + New(TypeTree(defn.EnumValuesType.appliedTo(enumClass.typeRef :: Nil)), ListOfNil)) + .withFlags(Private) + val valueOfDef = enumDefDef("enumValue", "fromInt") + val withNameDef = enumDefDef("enumValueNamed", "fromName") + val valuesDef = enumDefDef("enumValues", "values") + List(privateValuesDef, valueOfDef, withNameDef, valuesDef) } /** A creation method for a value of enum type `E`, which is defined as follows: @@ -198,7 +196,8 @@ object DesugarEnums { /** Expand a module definition representing a parameterless enum case */ def expandEnumModule(name: TermName, impl: Template, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree = { assert(impl.body.isEmpty) - if (impl.parents.isEmpty) + if (!enumClass.exists) EmptyTree + else if (impl.parents.isEmpty) expandSimpleEnumCase(name, mods, pos) else { def toStringMeth = @@ -213,8 +212,7 @@ object DesugarEnums { /** Expand a simple enum case */ def expandSimpleEnumCase(name: TermName, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree = - if (!enumClass.exists) EmptyTree - else if (enumClass.typeParams.nonEmpty) { + if (enumClass.typeParams.nonEmpty) { val parent = interpolatedEnumParent(pos) val impl = Template(emptyConstructor, parent :: Nil, EmptyValDef, Nil) expandEnumModule(name, impl, mods, pos) From 07065fa6da0e7b05e5da1b89a7790b7324919bb3 Mon Sep 17 00:00:00 2001 From: Sebastian Nadorp Date: Tue, 15 May 2018 23:13:36 +0200 Subject: [PATCH 06/10] Rename test cases --- tests/neg/{enum-repeated-4470.scala => i4470a.scala} | 0 .../{enum-repeated-extend-4470.scala => i4470b.scala} | 0 tests/neg/i4470c.scala | 9 +++++++++ 3 files changed, 9 insertions(+) rename tests/neg/{enum-repeated-4470.scala => i4470a.scala} (100%) rename tests/neg/{enum-repeated-extend-4470.scala => i4470b.scala} (100%) create mode 100644 tests/neg/i4470c.scala diff --git a/tests/neg/enum-repeated-4470.scala b/tests/neg/i4470a.scala similarity index 100% rename from tests/neg/enum-repeated-4470.scala rename to tests/neg/i4470a.scala diff --git a/tests/neg/enum-repeated-extend-4470.scala b/tests/neg/i4470b.scala similarity index 100% rename from tests/neg/enum-repeated-extend-4470.scala rename to tests/neg/i4470b.scala diff --git a/tests/neg/i4470c.scala b/tests/neg/i4470c.scala new file mode 100644 index 000000000000..b5f222905bce --- /dev/null +++ b/tests/neg/i4470c.scala @@ -0,0 +1,9 @@ +object DuplicatedEnum { + enum Maybe[+T] { // error // error + case Some(x: T) + } + + enum Maybe[+T] { // error + case Some(x: T) + } +} From 98f2460a67ad9e6ea8687d0dae9425de936803cb Mon Sep 17 00:00:00 2001 From: Sebastian Nadorp Date: Tue, 15 May 2018 23:30:51 +0200 Subject: [PATCH 07/10] Return empty TypeTree when enumClass is nonexistent For all calls to DesugarEnum. This renders the old fix obbsolete. --- compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala index 3bcb2ab8d344..4ffd8427d094 100644 --- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala +++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala @@ -64,7 +64,8 @@ object DesugarEnums { } /** A type tree referring to `enumClass` */ - def enumClassRef(implicit ctx: Context) = TypeTree(enumClass.typeRef) + def enumClassRef(implicit ctx: Context) = + if (enumClass.exists) TypeTree(enumClass.typeRef) else TypeTree() /** Add implied flags to an enum class or an enum case */ def addEnumFlags(cdef: TypeDef)(implicit ctx: Context) = @@ -87,7 +88,6 @@ object DesugarEnums { private def enumScaffolding(implicit ctx: Context): List[Tree] = { def enumDefDef(name: String, select: String) = DefDef(name.toTermName, Nil, Nil, TypeTree(), valuesDot(select)) - val privateValuesDef = ValDef(nme.DOLLAR_VALUES, TypeTree(), New(TypeTree(defn.EnumValuesType.appliedTo(enumClass.typeRef :: Nil)), ListOfNil)) @@ -196,8 +196,7 @@ object DesugarEnums { /** Expand a module definition representing a parameterless enum case */ def expandEnumModule(name: TermName, impl: Template, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree = { assert(impl.body.isEmpty) - if (!enumClass.exists) EmptyTree - else if (impl.parents.isEmpty) + if (impl.parents.isEmpty) expandSimpleEnumCase(name, mods, pos) else { def toStringMeth = From 0b0e616a66fe1afbca2c763bf7b5dac828cd1a38 Mon Sep 17 00:00:00 2001 From: Sebastian Nadorp Date: Wed, 16 May 2018 00:25:10 +0200 Subject: [PATCH 08/10] Only expand the tree if no errors are reported. --- compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala | 3 +-- compiler/src/dotty/tools/dotc/typer/Namer.scala | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala index 4ffd8427d094..59e57225b552 100644 --- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala +++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala @@ -64,8 +64,7 @@ object DesugarEnums { } /** A type tree referring to `enumClass` */ - def enumClassRef(implicit ctx: Context) = - if (enumClass.exists) TypeTree(enumClass.typeRef) else TypeTree() + def enumClassRef(implicit ctx: Context) = TypeTree(enumClass.typeRef) /** Add implied flags to an enum class or an enum case */ def addEnumFlags(cdef: TypeDef)(implicit ctx: Context) = diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 2d6ecae78fe4..d4797e5f5cf2 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -415,7 +415,7 @@ class Namer { typer: Typer => /** Expand tree and store in `expandedTree` */ def expand(tree: Tree)(implicit ctx: Context): Unit = tree match { - case mdef: DefTree => + case mdef: DefTree if !ctx.reporter.hasErrors => val expanded = desugar.defTree(mdef) typr.println(i"Expansion: $mdef expands to $expanded") if (expanded ne mdef) mdef.pushAttachment(ExpandedTree, expanded) From e5e91f15dcbe22358220886e9aabf39213574eec Mon Sep 17 00:00:00 2001 From: Sebastian Nadorp Date: Wed, 16 May 2018 01:00:04 +0200 Subject: [PATCH 09/10] Revert "Only expand the tree if no errors are reported." This reverts commit 0b0e616a66fe1afbca2c763bf7b5dac828cd1a38. --- compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala | 3 ++- compiler/src/dotty/tools/dotc/typer/Namer.scala | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala index 59e57225b552..4ffd8427d094 100644 --- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala +++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala @@ -64,7 +64,8 @@ object DesugarEnums { } /** A type tree referring to `enumClass` */ - def enumClassRef(implicit ctx: Context) = TypeTree(enumClass.typeRef) + def enumClassRef(implicit ctx: Context) = + if (enumClass.exists) TypeTree(enumClass.typeRef) else TypeTree() /** Add implied flags to an enum class or an enum case */ def addEnumFlags(cdef: TypeDef)(implicit ctx: Context) = diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index d4797e5f5cf2..2d6ecae78fe4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -415,7 +415,7 @@ class Namer { typer: Typer => /** Expand tree and store in `expandedTree` */ def expand(tree: Tree)(implicit ctx: Context): Unit = tree match { - case mdef: DefTree if !ctx.reporter.hasErrors => + case mdef: DefTree => val expanded = desugar.defTree(mdef) typr.println(i"Expansion: $mdef expands to $expanded") if (expanded ne mdef) mdef.pushAttachment(ExpandedTree, expanded) From 8cd413f316f86df9c5e39bd1d638eb7ece4ef596 Mon Sep 17 00:00:00 2001 From: Sebastian Nadorp Date: Wed, 16 May 2018 01:04:23 +0200 Subject: [PATCH 10/10] Reintroduce `enumClass.exists` --- compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala index 4ffd8427d094..925d3f74c415 100644 --- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala +++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala @@ -196,7 +196,8 @@ object DesugarEnums { /** Expand a module definition representing a parameterless enum case */ def expandEnumModule(name: TermName, impl: Template, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree = { assert(impl.body.isEmpty) - if (impl.parents.isEmpty) + if (!enumClass.exists) EmptyTree + else if (impl.parents.isEmpty) expandSimpleEnumCase(name, mods, pos) else { def toStringMeth = @@ -211,7 +212,8 @@ object DesugarEnums { /** Expand a simple enum case */ def expandSimpleEnumCase(name: TermName, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree = - if (enumClass.typeParams.nonEmpty) { + if (!enumClass.exists) EmptyTree + else if (enumClass.typeParams.nonEmpty) { val parent = interpolatedEnumParent(pos) val impl = Template(emptyConstructor, parent :: Nil, EmptyValDef, Nil) expandEnumModule(name, impl, mods, pos)