From 15c4964a3c06ec4c779fa227d79c9c2df110ad93 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 19 Jan 2021 16:11:14 +0100 Subject: [PATCH] Disallow case classes defined in inline methods --- .../dotty/tools/dotc/reporting/ErrorMessageID.scala | 3 ++- .../src/dotty/tools/dotc/reporting/messages.scala | 11 +++++++++++ .../dotty/tools/dotc/transform/PCPCheckAndHeal.scala | 4 +++- .../dotty/tools/dotc/typer/PrepareInlineable.scala | 8 ++++++-- tests/{pos-macros => neg-macros}/i4396b.scala | 2 +- tests/neg-macros/i7068-c.scala | 9 +++++++++ tests/{pos => neg}/i7068-a.scala | 2 +- tests/{pos => neg}/i7068-b.scala | 2 +- 8 files changed, 34 insertions(+), 7 deletions(-) rename tests/{pos-macros => neg-macros}/i4396b.scala (60%) create mode 100644 tests/neg-macros/i7068-c.scala rename tests/{pos => neg}/i7068-a.scala (79%) rename tests/{pos => neg}/i7068-b.scala (65%) diff --git a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala index c7999b6e209d..824fdc177bad 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala @@ -169,7 +169,8 @@ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID] { InvalidReferenceInImplicitNotFoundAnnotationID, TraitMayNotDefineNativeMethodID, JavaEnumParentArgsID, - AlreadyDefinedID + AlreadyDefinedID, + CaseClassInInlinedCodeID def errorNumber = ordinal - 2 } diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index f79ae8e2c929..b06bdfea1621 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -2500,3 +2500,14 @@ import transform.SymUtils._ |""".stripMargin def explain = "" } + + class CaseClassInInlinedCode(tree: tpd.Tree)(using Context) + extends SyntaxMsg(CaseClassInInlinedCodeID) { + + def defKind = if tree.symbol.is(Module) then "object" else "class" + def msg = s"Case $defKind definitions are not allowed in inline methods or quoted code. Use a normal $defKind instead." + def explain = + em"""Case class/object definitions generate a considerable fooprint in code size. + |Inlining such definition would multiply this footprint for each call site. + |""".stripMargin + } diff --git a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala index 15d76b88a13f..f999be7d2e29 100644 --- a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala +++ b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala @@ -93,7 +93,9 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( checkAnnotations(tree) healInfo(tree, tree.srcPos) super.transform(tree) - + case tree: TypeDef if tree.symbol.is(Case) && level > 0 => + report.error(reporting.CaseClassInInlinedCode(tree), tree) + super.transform(tree) case _ => super.transform(tree) } diff --git a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala index 46bfbbdeeba6..84ff8790f94d 100644 --- a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala +++ b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala @@ -177,7 +177,11 @@ object PrepareInlineable { // myAccessors += TypeDef(accessor).withPos(tree.pos.focus) // ref(accessor).withSpan(tree.span) // - case _ => tree + case _: TypeDef if tree.symbol.is(Case) => + report.error(reporting.CaseClassInInlinedCode(tree), tree) + tree + case _ => + tree } } @@ -251,7 +255,7 @@ object PrepareInlineable { } } - def checkInlineMethod(inlined: Symbol, body: Tree)(using Context): body.type = { + private def checkInlineMethod(inlined: Symbol, body: Tree)(using Context): body.type = { if (inlined.owner.isClass && inlined.owner.seesOpaques) report.error(em"Implementation restriction: No inline methods allowed where opaque type aliases are in scope", inlined.srcPos) if Inliner.inInlineMethod(using ctx.outer) then diff --git a/tests/pos-macros/i4396b.scala b/tests/neg-macros/i4396b.scala similarity index 60% rename from tests/pos-macros/i4396b.scala rename to tests/neg-macros/i4396b.scala index e1195dac7ab5..f5c4eb2d7fba 100644 --- a/tests/pos-macros/i4396b.scala +++ b/tests/neg-macros/i4396b.scala @@ -1,4 +1,4 @@ import scala.quoted._ def test(using Quotes) = { - '{ case class Foo() } + '{ case class Foo() } // error } \ No newline at end of file diff --git a/tests/neg-macros/i7068-c.scala b/tests/neg-macros/i7068-c.scala new file mode 100644 index 000000000000..7c6714d525c0 --- /dev/null +++ b/tests/neg-macros/i7068-c.scala @@ -0,0 +1,9 @@ +def species(using quoted.Quotes) = '{ + case object Bar // error + case class FooT() // error + ${ + case object Baz // ok + ??? + } + FooT() +} diff --git a/tests/pos/i7068-a.scala b/tests/neg/i7068-a.scala similarity index 79% rename from tests/pos/i7068-a.scala rename to tests/neg/i7068-a.scala index 577403f045d6..7fb6179859c9 100644 --- a/tests/pos/i7068-a.scala +++ b/tests/neg/i7068-a.scala @@ -3,7 +3,7 @@ sealed trait Foo[T] { } inline def species[T](t: T) = { - case class FooT(x: T) extends Foo[T] { + case class FooT(x: T) extends Foo[T] { // error def foo(s: Foo[T]) = s match { case FooT(x) => ??? } diff --git a/tests/pos/i7068-b.scala b/tests/neg/i7068-b.scala similarity index 65% rename from tests/pos/i7068-b.scala rename to tests/neg/i7068-b.scala index fcb24df9e140..63fea1291dbb 100644 --- a/tests/pos/i7068-b.scala +++ b/tests/neg/i7068-b.scala @@ -1,5 +1,5 @@ inline def species() = { - case class FooT() + case class FooT() // error FooT() } val foo = species()