Skip to content

Commit b74b492

Browse files
authored
Merge pull request #3865 from dotty-staging/fix/java-default-annot
Fix #2760: Support defaults in Java annotations parsed from sources
2 parents 8f069b0 + a1a1a4b commit b74b492

File tree

4 files changed

+34
-6
lines changed

4 files changed

+34
-6
lines changed

compiler/src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ object StdNames {
440440
val in: N = "in"
441441
val info: N = "info"
442442
val inlinedEquals: N = "inlinedEquals"
443+
val internal: N = "internal"
443444
val isArray: N = "isArray"
444445
val isDefinedAt: N = "isDefinedAt"
445446
val isDefinedAtImpl: N = "$isDefinedAt"

compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ object JavaParsers {
123123
// A dummy first constructor is needed for Java classes so that the real constructors see the
124124
// import of the companion object. The constructor has parameter of type Unit so no Java code
125125
// can call it.
126+
// This also avoids clashes between the constructor parameter names and member names.
126127
if (needsDummyConstr) {
127128
stats1 = constr1 :: stats1
128129
constr1 = makeConstructor(List(scalaDot(tpnme.Unit)), tparams, Flags.JavaDefined | Flags.PrivateLocal)
@@ -132,8 +133,8 @@ object JavaParsers {
132133

133134
def makeSyntheticParam(count: Int, tpt: Tree): ValDef =
134135
makeParam(nme.syntheticParamName(count), tpt)
135-
def makeParam(name: TermName, tpt: Tree): ValDef =
136-
ValDef(name, tpt, EmptyTree).withMods(Modifiers(Flags.JavaDefined | Flags.ParamAccessor))
136+
def makeParam(name: TermName, tpt: Tree, defaultValue: Tree = EmptyTree): ValDef =
137+
ValDef(name, tpt, defaultValue).withMods(Modifiers(Flags.JavaDefined | Flags.Param))
137138

138139
def makeConstructor(formals: List[Tree], tparams: List[TypeDef], flags: FlagSet = Flags.JavaDefined) = {
139140
val vparams = formals.zipWithIndex.map { case (p, i) => makeSyntheticParam(i + 1, p) }
@@ -515,7 +516,7 @@ object JavaParsers {
515516
if (parentToken == AT && in.token == DEFAULT) {
516517
val annot =
517518
atPos(nameOffset) {
518-
New(Select(scalaDot(nme.runtime), tpnme.AnnotationDefaultATTR), Nil)
519+
New(Select(Select(scalaDot(nme.annotation), nme.internal), tpnme.AnnotationDefaultATTR), Nil)
519520
}
520521
mods1 = mods1 withAddedAnnotation annot
521522
val unimplemented = unimplementedExpr
@@ -772,12 +773,22 @@ object JavaParsers {
772773
val name = identForType()
773774
val (statics, body) = typeBody(AT, name, List())
774775
val constructorParams = body.collect {
775-
case dd: DefDef => makeParam(dd.name, dd.tpt)
776+
case dd: DefDef =>
777+
val hasDefault =
778+
dd.mods.annotations.exists {
779+
case Apply(Select(New(Select(_, tpnme.AnnotationDefaultATTR)), nme.CONSTRUCTOR), Nil) =>
780+
true
781+
case _ =>
782+
false
783+
}
784+
// If the annotation has a default value we don't need to parse it, providing
785+
// any value at all is enough to typecheck usages of annotations correctly.
786+
val defaultParam = if (hasDefault) unimplementedExpr else EmptyTree
787+
makeParam(dd.name, dd.tpt, defaultParam)
776788
}
777789
val constr = DefDef(nme.CONSTRUCTOR,
778790
List(), List(constructorParams), TypeTree(), EmptyTree).withMods(Modifiers(Flags.JavaDefined))
779-
val body1 = body.filterNot(_.isInstanceOf[DefDef])
780-
val templ = makeTemplate(annotationParents, constr :: body1, List(), false)
791+
val templ = makeTemplate(annotationParents, constr :: body, List(), true)
781792
val annot = atPos(start, nameOffset) {
782793
TypeDef(name, templ).withMods(mods | Flags.Abstract)
783794
}

tests/run/i2760/Fork.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import java.lang.annotation.*;
2+
3+
@Retention(RetentionPolicy.RUNTIME)
4+
public @interface Fork {
5+
int value() default -1;
6+
int warmups() default -1;
7+
}

tests/run/i2760/Test.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@Fork(value = 16) class HasFork
2+
3+
object Test {
4+
def main(args: Array[String]): Unit = {
5+
val fork = classOf[HasFork].getAnnotation(classOf[Fork])
6+
assert(fork.value == 16, s"fork.value is ${fork.value} but should have been 16")
7+
assert(fork.warmups == -1, s"fork.warmups is ${fork.warmups} but should have been -1")
8+
}
9+
}

0 commit comments

Comments
 (0)