diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala index 79282b0e5223..fd0ae45e3fc6 100644 --- a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -440,11 +440,11 @@ object JavaParsers { } } - def modifiers(inInterface: Boolean): Modifiers = { + def modifiers(inInterface: Boolean, annots0: List[Tree] = Nil): Modifiers = { var flags: FlagSet = Flags.JavaDefined // assumed true unless we see public/private/protected var isPackageAccess = true - var annots = new ListBuffer[Tree] + var annots = ListBuffer.from[Tree](annots0) def addAnnot(tpt: Tree) = annots += atSpan(in.offset) { in.nextToken() @@ -453,7 +453,7 @@ object JavaParsers { while (true) in.token match { - case AT if (in.lookaheadToken != INTERFACE) => + case AT if in.lookaheadToken != INTERFACE => in.nextToken() annotation() match { case Some(anno) => annots += anno @@ -1080,24 +1080,30 @@ object JavaParsers { /** CompilationUnit ::= [package QualId semi] TopStatSeq */ def compilationUnit(): Tree = { - val start = in.offset + val buf = ListBuffer.empty[Tree] + var start = in.offset + val leadingAnnots = if (in.token == AT) annotations() else Nil val pkg: RefTree = - if (in.token == AT || in.token == PACKAGE) { - annotations() + if in.token == PACKAGE then + if !leadingAnnots.isEmpty then + //if (unit.source.file.name != "package-info.java") + // syntaxError(pos, "package annotations must be in file package-info.java") + start = in.offset accept(PACKAGE) val pkg = qualId() accept(SEMI) pkg - } else + if !leadingAnnots.isEmpty then + buf ++= typeDecl(start, modifiers(inInterface = false, annots0 = leadingAnnots)) Ident(nme.EMPTY_PACKAGE) thisPackageName = convertToTypeName(pkg) match { case Some(t) => t.name.toTypeName case _ => tpnme.EMPTY } - val buf = new ListBuffer[Tree] - while (in.token == IMPORT) - buf ++= importDecl() + if buf.isEmpty then + while in.token == IMPORT do + buf ++= importDecl() while (in.token != EOF && in.token != RBRACE) { while (in.token == SEMI) in.nextToken() if (in.token != EOF) { diff --git a/tests/pos/i20026/Empty.java b/tests/pos/i20026/Empty.java new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/pos/i20026/JFun.java b/tests/pos/i20026/JFun.java new file mode 100644 index 000000000000..d2109909c3e0 --- /dev/null +++ b/tests/pos/i20026/JFun.java @@ -0,0 +1,4 @@ +@FunctionalInterface +public interface JFun { + String f(String s); +} diff --git a/tests/pos/i20026/JTest.java b/tests/pos/i20026/JTest.java new file mode 100644 index 000000000000..c91f533383b5 --- /dev/null +++ b/tests/pos/i20026/JTest.java @@ -0,0 +1,4 @@ + +@api.TestInstance(api.TestInstance.Lifecycle.PER_CLASS) +public class JTest { +} diff --git a/tests/pos/i20026/KTest.java b/tests/pos/i20026/KTest.java new file mode 100644 index 000000000000..9b32932e780c --- /dev/null +++ b/tests/pos/i20026/KTest.java @@ -0,0 +1,6 @@ + +import api.*; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class KTest { +} diff --git a/tests/pos/i20026/TestInstance.java b/tests/pos/i20026/TestInstance.java new file mode 100644 index 000000000000..11cca9698664 --- /dev/null +++ b/tests/pos/i20026/TestInstance.java @@ -0,0 +1,20 @@ + +package api; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface TestInstance { + enum Lifecycle { + PER_CLASS; + } + Lifecycle value(); +} diff --git a/tests/pos/i20026/test.scala b/tests/pos/i20026/test.scala new file mode 100644 index 000000000000..792e10c36d61 --- /dev/null +++ b/tests/pos/i20026/test.scala @@ -0,0 +1,6 @@ + +object Test extends App { + println { + new JTest + } +}