diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 23897efecfe..0f9bb38caae 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -445,16 +445,16 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { } } - def modifiers(inInterface: Boolean): Modifiers = { + def modifiers(inInterface: Boolean, annots0: List[Tree] = Nil): Modifiers = { var flags: Long = Flags.JAVA // assumed true unless we see public/private/protected var isPackageAccess = true - var annots: List[Tree] = Nil + var annots: List[Tree] = annots0 def addAnnot(sym: Symbol) = annots :+= New(sym.tpe) while (true) { in.token match { - case AT if (in.lookaheadToken != INTERFACE) => + case AT if in.lookaheadToken != INTERFACE => in.nextToken() val annot = annotation() if (annot.nonEmpty) annots :+= annot @@ -1086,28 +1086,34 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { else Some(Constant(l)) } - /** CompilationUnit ::= [package QualId semi] TopStatSeq + /** CompilationUnit ::= [[Annotation] package QualId semi] {Import} {TypeDecl} //TopStatSeq */ def compilationUnit(): Tree = { + val buf = ListBuffer.empty[Tree] var pos = in.currentPos + val leadingAnnots = if (in.token == AT) annotations() else Nil val pkg: RefTree = - if (in.token == AT || in.token == PACKAGE) { - annotations() // TODO: put these somewhere? - pos = in.currentPos + if (in.token == PACKAGE) { + if (!leadingAnnots.isEmpty) { // TODO: put these somewhere? + //if (unit.source.file.name != "package-info.java") + // syntaxError(pos, "package annotations must be in file package-info.java") + pos = in.currentPos + } accept(PACKAGE) - val pkg = qualId().asInstanceOf[RefTree] - accept(SEMI) - pkg - } else { + qualId().asInstanceOf[RefTree].tap(_ => accept(SEMI)) + } + else { + if (!leadingAnnots.isEmpty) + buf ++= typeDecl(modifiers(inInterface = false, annots0 = leadingAnnots)) Ident(nme.EMPTY_PACKAGE_NAME) } thisPackageName = gen.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) + while (in.token == IMPORT) + buf ++= importDecl() while (in.token != EOF && in.token != RBRACE) { while (in.token == SEMI) in.nextToken() if (in.token != EOF) diff --git a/test/files/neg/i20026.check b/test/files/neg/i20026.check new file mode 100644 index 00000000000..1686b904097 --- /dev/null +++ b/test/files/neg/i20026.check @@ -0,0 +1,4 @@ +JTest.java:3: error: illegal start of type declaration +import java.util.*; + ^ +1 error diff --git a/test/files/neg/i20026/JTest.java b/test/files/neg/i20026/JTest.java new file mode 100644 index 00000000000..c0f9ffa1a88 --- /dev/null +++ b/test/files/neg/i20026/JTest.java @@ -0,0 +1,6 @@ + +@Deprecated +import java.util.*; + +public class JTest { +} diff --git a/test/files/neg/i20026/p.java b/test/files/neg/i20026/p.java new file mode 100644 index 00000000000..a6fc2f1597d --- /dev/null +++ b/test/files/neg/i20026/p.java @@ -0,0 +1,2 @@ +@Deprecated +package p; diff --git a/test/files/neg/i20026/test.scala b/test/files/neg/i20026/test.scala new file mode 100644 index 00000000000..792e10c36d6 --- /dev/null +++ b/test/files/neg/i20026/test.scala @@ -0,0 +1,6 @@ + +object Test extends App { + println { + new JTest + } +} diff --git a/test/files/pos/i20026/Empty.java b/test/files/pos/i20026/Empty.java new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/files/pos/i20026/JFun.java b/test/files/pos/i20026/JFun.java new file mode 100644 index 00000000000..d2109909c3e --- /dev/null +++ b/test/files/pos/i20026/JFun.java @@ -0,0 +1,4 @@ +@FunctionalInterface +public interface JFun { + String f(String s); +} diff --git a/test/files/pos/i20026/JTest.java b/test/files/pos/i20026/JTest.java new file mode 100644 index 00000000000..c91f533383b --- /dev/null +++ b/test/files/pos/i20026/JTest.java @@ -0,0 +1,4 @@ + +@api.TestInstance(api.TestInstance.Lifecycle.PER_CLASS) +public class JTest { +} diff --git a/test/files/pos/i20026/KTest.java b/test/files/pos/i20026/KTest.java new file mode 100644 index 00000000000..9b32932e780 --- /dev/null +++ b/test/files/pos/i20026/KTest.java @@ -0,0 +1,6 @@ + +import api.*; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class KTest { +} diff --git a/test/files/pos/i20026/TestInstance.java b/test/files/pos/i20026/TestInstance.java new file mode 100644 index 00000000000..11cca969866 --- /dev/null +++ b/test/files/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/test/files/pos/i20026/test.scala b/test/files/pos/i20026/test.scala new file mode 100644 index 00000000000..838788d8592 --- /dev/null +++ b/test/files/pos/i20026/test.scala @@ -0,0 +1,6 @@ + +object Test extends App { + println { + (new JTest, new KTest, ((s: String) => s): JFun) + } +}