From f113fc075000d76043508299dd5954e2e159564e Mon Sep 17 00:00:00 2001 From: Tom Grigg Date: Thu, 28 Apr 2022 16:37:36 -0700 Subject: [PATCH 1/2] Rename `@targetName` related tests: alpha -> targetName Cleanup some leftovers from when `@targetName` was called `@alpha`. --- compiler/test/dotty/tools/dotc/CompilationTests.scala | 2 +- .../{missing-alpha.scala => missing-targetName.scala} | 0 tests/neg/{alpha-early.scala => targetName-early.scala} | 0 tests/neg/{alpha-late.scala => targetName-late.scala} | 0 tests/neg/{alpha-override => targetName-override0}/B_1.java | 0 tests/neg/{alpha-override => targetName-override0}/C_2.scala | 0 tests/neg/{alpha-override1 => targetName-override1}/B_1.java | 0 tests/neg/{alpha-override1 => targetName-override1}/D_2.scala | 0 tests/pos/{alpha-override => targetName-override}/A_1.scala | 0 tests/pos/{alpha-override => targetName-override}/B_2.java | 0 tests/pos/{alpha.scala => targetName.scala} | 0 tests/run/{alpha-interop => targetName-interop}/Test_2.java | 0 tests/run/{alpha-interop => targetName-interop}/Test_3.scala | 0 tests/run/{alpha-interop => targetName-interop}/alpha_1.scala | 0 .../run/{alpha-modules-1 => targetName-modules-1}/7721_1.scala | 0 tests/run/{alpha-modules-1 => targetName-modules-1}/Test_2.java | 0 .../run/{alpha-modules-1 => targetName-modules-1}/Test_3.scala | 0 .../run/{alpha-modules-2 => targetName-modules-2}/7723_1.scala | 0 tests/run/{alpha-modules-2 => targetName-modules-2}/Test_2.java | 0 .../run/{alpha-modules-2 => targetName-modules-2}/Test_3.scala | 0 tests/run/{alpha.scala => targetName1.scala} | 0 21 files changed, 1 insertion(+), 1 deletion(-) rename tests/neg-custom-args/{missing-alpha.scala => missing-targetName.scala} (100%) rename tests/neg/{alpha-early.scala => targetName-early.scala} (100%) rename tests/neg/{alpha-late.scala => targetName-late.scala} (100%) rename tests/neg/{alpha-override => targetName-override0}/B_1.java (100%) rename tests/neg/{alpha-override => targetName-override0}/C_2.scala (100%) rename tests/neg/{alpha-override1 => targetName-override1}/B_1.java (100%) rename tests/neg/{alpha-override1 => targetName-override1}/D_2.scala (100%) rename tests/pos/{alpha-override => targetName-override}/A_1.scala (100%) rename tests/pos/{alpha-override => targetName-override}/B_2.java (100%) rename tests/pos/{alpha.scala => targetName.scala} (100%) rename tests/run/{alpha-interop => targetName-interop}/Test_2.java (100%) rename tests/run/{alpha-interop => targetName-interop}/Test_3.scala (100%) rename tests/run/{alpha-interop => targetName-interop}/alpha_1.scala (100%) rename tests/run/{alpha-modules-1 => targetName-modules-1}/7721_1.scala (100%) rename tests/run/{alpha-modules-1 => targetName-modules-1}/Test_2.java (100%) rename tests/run/{alpha-modules-1 => targetName-modules-1}/Test_3.scala (100%) rename tests/run/{alpha-modules-2 => targetName-modules-2}/7723_1.scala (100%) rename tests/run/{alpha-modules-2 => targetName-modules-2}/Test_2.java (100%) rename tests/run/{alpha-modules-2 => targetName-modules-2}/Test_3.scala (100%) rename tests/run/{alpha.scala => targetName1.scala} (100%) diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 5681bd480511..c8082069c28f 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -171,7 +171,7 @@ class CompilationTests { defaultOptions), compileFile("tests/neg-custom-args/i6300.scala", allowDeepSubtypes), compileFile("tests/neg-custom-args/infix.scala", defaultOptions.and("-source", "future", "-deprecation", "-Xfatal-warnings")), - compileFile("tests/neg-custom-args/missing-alpha.scala", defaultOptions.and("-Yrequire-targetName", "-Xfatal-warnings")), + compileFile("tests/neg-custom-args/missing-targetName.scala", defaultOptions.and("-Yrequire-targetName", "-Xfatal-warnings")), compileFile("tests/neg-custom-args/wildcards.scala", defaultOptions.and("-source", "future", "-deprecation", "-Xfatal-warnings")), compileFile("tests/neg-custom-args/indentRight.scala", defaultOptions.and("-no-indent", "-Xfatal-warnings")), compileDir("tests/neg-custom-args/adhoc-extension", defaultOptions.and("-source", "future", "-feature", "-Xfatal-warnings")), diff --git a/tests/neg-custom-args/missing-alpha.scala b/tests/neg-custom-args/missing-targetName.scala similarity index 100% rename from tests/neg-custom-args/missing-alpha.scala rename to tests/neg-custom-args/missing-targetName.scala diff --git a/tests/neg/alpha-early.scala b/tests/neg/targetName-early.scala similarity index 100% rename from tests/neg/alpha-early.scala rename to tests/neg/targetName-early.scala diff --git a/tests/neg/alpha-late.scala b/tests/neg/targetName-late.scala similarity index 100% rename from tests/neg/alpha-late.scala rename to tests/neg/targetName-late.scala diff --git a/tests/neg/alpha-override/B_1.java b/tests/neg/targetName-override0/B_1.java similarity index 100% rename from tests/neg/alpha-override/B_1.java rename to tests/neg/targetName-override0/B_1.java diff --git a/tests/neg/alpha-override/C_2.scala b/tests/neg/targetName-override0/C_2.scala similarity index 100% rename from tests/neg/alpha-override/C_2.scala rename to tests/neg/targetName-override0/C_2.scala diff --git a/tests/neg/alpha-override1/B_1.java b/tests/neg/targetName-override1/B_1.java similarity index 100% rename from tests/neg/alpha-override1/B_1.java rename to tests/neg/targetName-override1/B_1.java diff --git a/tests/neg/alpha-override1/D_2.scala b/tests/neg/targetName-override1/D_2.scala similarity index 100% rename from tests/neg/alpha-override1/D_2.scala rename to tests/neg/targetName-override1/D_2.scala diff --git a/tests/pos/alpha-override/A_1.scala b/tests/pos/targetName-override/A_1.scala similarity index 100% rename from tests/pos/alpha-override/A_1.scala rename to tests/pos/targetName-override/A_1.scala diff --git a/tests/pos/alpha-override/B_2.java b/tests/pos/targetName-override/B_2.java similarity index 100% rename from tests/pos/alpha-override/B_2.java rename to tests/pos/targetName-override/B_2.java diff --git a/tests/pos/alpha.scala b/tests/pos/targetName.scala similarity index 100% rename from tests/pos/alpha.scala rename to tests/pos/targetName.scala diff --git a/tests/run/alpha-interop/Test_2.java b/tests/run/targetName-interop/Test_2.java similarity index 100% rename from tests/run/alpha-interop/Test_2.java rename to tests/run/targetName-interop/Test_2.java diff --git a/tests/run/alpha-interop/Test_3.scala b/tests/run/targetName-interop/Test_3.scala similarity index 100% rename from tests/run/alpha-interop/Test_3.scala rename to tests/run/targetName-interop/Test_3.scala diff --git a/tests/run/alpha-interop/alpha_1.scala b/tests/run/targetName-interop/alpha_1.scala similarity index 100% rename from tests/run/alpha-interop/alpha_1.scala rename to tests/run/targetName-interop/alpha_1.scala diff --git a/tests/run/alpha-modules-1/7721_1.scala b/tests/run/targetName-modules-1/7721_1.scala similarity index 100% rename from tests/run/alpha-modules-1/7721_1.scala rename to tests/run/targetName-modules-1/7721_1.scala diff --git a/tests/run/alpha-modules-1/Test_2.java b/tests/run/targetName-modules-1/Test_2.java similarity index 100% rename from tests/run/alpha-modules-1/Test_2.java rename to tests/run/targetName-modules-1/Test_2.java diff --git a/tests/run/alpha-modules-1/Test_3.scala b/tests/run/targetName-modules-1/Test_3.scala similarity index 100% rename from tests/run/alpha-modules-1/Test_3.scala rename to tests/run/targetName-modules-1/Test_3.scala diff --git a/tests/run/alpha-modules-2/7723_1.scala b/tests/run/targetName-modules-2/7723_1.scala similarity index 100% rename from tests/run/alpha-modules-2/7723_1.scala rename to tests/run/targetName-modules-2/7723_1.scala diff --git a/tests/run/alpha-modules-2/Test_2.java b/tests/run/targetName-modules-2/Test_2.java similarity index 100% rename from tests/run/alpha-modules-2/Test_2.java rename to tests/run/targetName-modules-2/Test_2.java diff --git a/tests/run/alpha-modules-2/Test_3.scala b/tests/run/targetName-modules-2/Test_3.scala similarity index 100% rename from tests/run/alpha-modules-2/Test_3.scala rename to tests/run/targetName-modules-2/Test_3.scala diff --git a/tests/run/alpha.scala b/tests/run/targetName1.scala similarity index 100% rename from tests/run/alpha.scala rename to tests/run/targetName1.scala From 47189c79b138ed465822c782db6d08c43c35337b Mon Sep 17 00:00:00 2001 From: Tom Grigg Date: Thu, 28 Apr 2022 17:35:27 -0700 Subject: [PATCH 2/2] Disallow `@targetName` on top-level `class`, `trait`, and `object`. This usage was mostly broken, as it failed with separate compilation. --- .../tools/dotc/reporting/ErrorMessageID.scala | 3 ++- .../dotty/tools/dotc/reporting/messages.scala | 21 +++++++++++++++++++ .../src/dotty/tools/dotc/typer/Checking.scala | 2 ++ .../other-new-features/targetName.md | 2 +- tests/neg/targetName-toplevel.scala | 18 ++++++++++++++++ tests/run/targetName-interop/Test_2.java | 2 +- tests/run/targetName-interop/alpha_1.scala | 9 ++++---- tests/run/targetName-modules-1/7721_1.scala | 6 ++++-- tests/run/targetName-modules-1/Test_2.java | 4 ++-- tests/run/targetName-modules-2/7723_1.scala | 3 ++- tests/run/targetName-modules-2/Test_2.java | 6 +++--- tests/run/targetName-separate/Foo_1.scala | 5 +++++ tests/run/targetName-separate/Test_2.scala | 3 +++ 13 files changed, 69 insertions(+), 15 deletions(-) create mode 100644 tests/neg/targetName-toplevel.scala create mode 100644 tests/run/targetName-separate/Foo_1.scala create mode 100644 tests/run/targetName-separate/Test_2.scala diff --git a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala index 2f1fe0e1c058..69b70e0a1720 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala @@ -176,7 +176,8 @@ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID]: MatchableWarningID, CannotExtendFunctionID, LossyWideningConstantConversionID, - ImplicitSearchTooLargeID + ImplicitSearchTooLargeID, + TargetNameOnTopLevelClassID 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 797073115bb5..48135f9aa35d 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -2540,3 +2540,24 @@ import transform.SymUtils._ | |${openSearchPairs.reverse.map(showQuery)}%\n% """ + + class TargetNameOnTopLevelClass(symbol: Symbol)(using Context) + extends SyntaxMsg(TargetNameOnTopLevelClassID): + def msg = em"${hl("@targetName")} annotation not allowed on top-level $symbol" + def explain = + val annot = symbol.getAnnotation(defn.TargetNameAnnot).get + em"""The @targetName annotation may be applied to a top-level ${hl("val")} or ${hl("def")}, but not + |a top-level ${hl("class")}, ${hl("trait")}, or ${hl("object")}. + | + |This restriction is due to the naming convention of Java classfiles, whose filenames + |are based on the name of the class defined within. If @targetName were permitted + |here, the name of the classfile would be based on the target name, and the compiler + |could not associate that classfile with the Scala-visible defined name of the class. + | + |If your use case requires @targetName, consider wrapping $symbol in an ${hl("object")} + |(and possibly exporting it), as in the following example: + | + |${hl("object Wrapper:")} + | $annot $symbol { ... } + | + |${hl("export")} Wrapper.${symbol.name} ${hl("// optional")}""" diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 1e597e42d2a5..7b7bdd5945be 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -505,6 +505,8 @@ object Checking { fail(TailrecNotApplicable(sym)) else if sym.is(Inline) then fail("Inline methods cannot be @tailrec") + if sym.hasAnnotation(defn.TargetNameAnnot) && sym.isClass && sym.isTopLevelClass then + fail(TargetNameOnTopLevelClass(sym)) if (sym.hasAnnotation(defn.NativeAnnot)) { if (!sym.is(Deferred)) fail(NativeMembersMayNotHaveImplementation(sym)) diff --git a/docs/_docs/reference/other-new-features/targetName.md b/docs/_docs/reference/other-new-features/targetName.md index d2a654697d15..09886968a232 100644 --- a/docs/_docs/reference/other-new-features/targetName.md +++ b/docs/_docs/reference/other-new-features/targetName.md @@ -29,7 +29,7 @@ The [`@targetName`](https://scala-lang.org/api/3.x/scala/annotation/targetName.h of type `String`. That string is called the _external name_ of the definition that's annotated. - 2. A `@targetName` annotation can be given for all kinds of definitions. + 2. A `@targetName` annotation can be given for all kinds of definitions except a top-level `class`, `trait`, or `object`. 3. The name given in a [`@targetName`](https://scala-lang.org/api/3.x/scala/annotation/targetName.html) annotation must be a legal name for the defined entities on the host platform. diff --git a/tests/neg/targetName-toplevel.scala b/tests/neg/targetName-toplevel.scala new file mode 100644 index 000000000000..28e8b0e84ca3 --- /dev/null +++ b/tests/neg/targetName-toplevel.scala @@ -0,0 +1,18 @@ +import scala.annotation.targetName + +@targetName("B1") class A1 // error targetName on top-level class +@targetName("B2") trait A2 // error targetName on top-level trait +@targetName("B3") object A3 // error targetName on top-level object + +@targetName("bar") def foo = 42 // OK + +object Outer: + @targetName("B1") class A1 // OK + @targetName("B2") trait A2 // OK + @targetName("B3") object A3 // OK + @targetName("D1") class C1 // OK + @targetName("D2") trait C2 // OK + @targetName("D3") object C3 // OK + +export Outer.{A1, A2, A3} // error // error // error already defined +export Outer.{C1, C2, C3} // OK diff --git a/tests/run/targetName-interop/Test_2.java b/tests/run/targetName-interop/Test_2.java index 6e93f3cd3533..a1c710174c68 100644 --- a/tests/run/targetName-interop/Test_2.java +++ b/tests/run/targetName-interop/Test_2.java @@ -4,7 +4,7 @@ public class Test_2 { public static void main(String[] args) { - Alpha a = new Bar(); + Alpha a = new Outer$Bar(); assert a.foo() == 1; assert a.bar("a").equals("aa"); Alpha aa = a.append(a); diff --git a/tests/run/targetName-interop/alpha_1.scala b/tests/run/targetName-interop/alpha_1.scala index 41fb26c3f019..6408fccb48e5 100644 --- a/tests/run/targetName-interop/alpha_1.scala +++ b/tests/run/targetName-interop/alpha_1.scala @@ -11,10 +11,11 @@ abstract class Alpha[T] { } -@targetName("Bar") class | extends Alpha[String] { +object Outer { + @targetName("Bar") class | extends Alpha[String] { - @targetName("bar") override def foo(x: String) = x ++ x - - @targetName("append") override def ++ (xs: Alpha[String]) = this + @targetName("bar") override def foo(x: String) = x ++ x + @targetName("append") override def ++ (xs: Alpha[String]) = this + } } \ No newline at end of file diff --git a/tests/run/targetName-modules-1/7721_1.scala b/tests/run/targetName-modules-1/7721_1.scala index 5e59433c6beb..8420c14107ab 100644 --- a/tests/run/targetName-modules-1/7721_1.scala +++ b/tests/run/targetName-modules-1/7721_1.scala @@ -1,5 +1,7 @@ package alpha -@scala.annotation.targetName("A") object B { - def foo = 23 +object Outer { + @scala.annotation.targetName("A") object B { + def foo = 23 + } } diff --git a/tests/run/targetName-modules-1/Test_2.java b/tests/run/targetName-modules-1/Test_2.java index 2dbed46aa644..e92e602362c6 100644 --- a/tests/run/targetName-modules-1/Test_2.java +++ b/tests/run/targetName-modules-1/Test_2.java @@ -3,7 +3,7 @@ public class Test_2 { public static void main(String[] args) { - assert A.foo() == 23; - assert A$.MODULE$.foo() == 23; + assert Outer$.A.foo() == 23; + assert Outer$A$.MODULE$.foo() == 23; } } diff --git a/tests/run/targetName-modules-2/7723_1.scala b/tests/run/targetName-modules-2/7723_1.scala index 128dac508a14..8865c5ada577 100644 --- a/tests/run/targetName-modules-2/7723_1.scala +++ b/tests/run/targetName-modules-2/7723_1.scala @@ -1,3 +1,4 @@ package alpha -@scala.annotation.targetName("A") class B(val i: Int = 1) +object Outer: + @scala.annotation.targetName("A") class B(val i: Int = 1) diff --git a/tests/run/targetName-modules-2/Test_2.java b/tests/run/targetName-modules-2/Test_2.java index 39bdf269a98a..7d48407a6ded 100644 --- a/tests/run/targetName-modules-2/Test_2.java +++ b/tests/run/targetName-modules-2/Test_2.java @@ -3,8 +3,8 @@ public class Test_2 { public static void main(String[] args) { - assert new A(101).i() == 101; - assert new A(A.$lessinit$greater$default$1()).i() == 101; - assert new A(A$.MODULE$.$lessinit$greater$default$1()).i() == 101; + assert new Outer$A(101).i() == 101; + assert new Outer$A(Outer$A.$lessinit$greater$default$1()).i() == 101; + assert new Outer$A(Outer$A$.MODULE$.$lessinit$greater$default$1()).i() == 101; } } diff --git a/tests/run/targetName-separate/Foo_1.scala b/tests/run/targetName-separate/Foo_1.scala new file mode 100644 index 000000000000..dca3c888470c --- /dev/null +++ b/tests/run/targetName-separate/Foo_1.scala @@ -0,0 +1,5 @@ +object Outer: + @annotation.targetName("Bar") class Foo: + def it: Int = 42 + +export Outer.Foo diff --git a/tests/run/targetName-separate/Test_2.scala b/tests/run/targetName-separate/Test_2.scala new file mode 100644 index 000000000000..f051adde1531 --- /dev/null +++ b/tests/run/targetName-separate/Test_2.scala @@ -0,0 +1,3 @@ +@main def Test = + assert(new Foo().it == 42) + assert(Foo().it == 42)