From a05ffadc08b1a39dd3ec4c2f9889bb09858ca148 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 15 Dec 2019 21:11:28 +0100 Subject: [PATCH 1/3] Fix #7748: Don't allow classes to be defined in universal traits --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 4 ++++ tests/neg/i7748.scala | 11 +++++++++++ 2 files changed, 15 insertions(+) create mode 100644 tests/neg/i7748.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index b795ab296467..46e93bc3a8a6 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1810,6 +1810,10 @@ class Typer extends Namer // check value class constraints checkDerivedValueClass(cls, body1) + val effectiveOwner = cls.owner.skipWeakOwner + if !cls.isRefinementClass && effectiveOwner.is(Trait) && !effectiveOwner.derivesFrom(defn.ObjectClass) + ctx.error(i"class $cls cannot be defined in universal $effectiveOwner", cdef.sourcePos) + // Temporarily set the typed class def as root tree so that we have at least some // information in the IDE in case we never reach `SetRootTree`. if (ctx.mode.is(Mode.Interactive) && ctx.settings.YretainTrees.value) diff --git a/tests/neg/i7748.scala b/tests/neg/i7748.scala new file mode 100644 index 000000000000..60574fbf6182 --- /dev/null +++ b/tests/neg/i7748.scala @@ -0,0 +1,11 @@ +trait A extends Any { + case class B() // error + val x = { + case class C() // error + 1 + } + def f = { + case class C() // ok + 1 + } +} \ No newline at end of file From 7d0ab6f4f5df4cd389350f992e980d066867b956 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 15 Dec 2019 23:36:28 +0100 Subject: [PATCH 2/3] Disallow only case classes --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 46e93bc3a8a6..a050bfefcf3c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1811,8 +1811,8 @@ class Typer extends Namer checkDerivedValueClass(cls, body1) val effectiveOwner = cls.owner.skipWeakOwner - if !cls.isRefinementClass && effectiveOwner.is(Trait) && !effectiveOwner.derivesFrom(defn.ObjectClass) - ctx.error(i"class $cls cannot be defined in universal $effectiveOwner", cdef.sourcePos) + if cls.is(CaseClass) && effectiveOwner.is(Trait) && !effectiveOwner.derivesFrom(defn.ObjectClass) + ctx.error(i"case $cls cannot be defined in universal $effectiveOwner", cdef.sourcePos) // Temporarily set the typed class def as root tree so that we have at least some // information in the IDE in case we never reach `SetRootTree`. From 3d69d057d06c9473c2f807596e913c065107120e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 16 Dec 2019 18:46:28 +0100 Subject: [PATCH 3/3] Adopt review suggestions --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index a050bfefcf3c..50b973983c83 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1811,8 +1811,11 @@ class Typer extends Namer checkDerivedValueClass(cls, body1) val effectiveOwner = cls.owner.skipWeakOwner - if cls.is(CaseClass) && effectiveOwner.is(Trait) && !effectiveOwner.derivesFrom(defn.ObjectClass) - ctx.error(i"case $cls cannot be defined in universal $effectiveOwner", cdef.sourcePos) + if !cls.isRefinementClass + && !cls.isAllOf(PrivateLocal) + && effectiveOwner.is(Trait) + && !effectiveOwner.derivesFrom(defn.ObjectClass) + ctx.error(i"$cls cannot be defined in universal $effectiveOwner", cdef.sourcePos) // Temporarily set the typed class def as root tree so that we have at least some // information in the IDE in case we never reach `SetRootTree`.