Skip to content

Commit 275d891

Browse files
committed
Make sure all arguments to Java annot constructors are NamedArg's.
The Java model of annotations is unordered and name-based. Even though we typecheck things from source with a particular ordering, semantically we must always use `NamedArg`s to match the Java model.
1 parent cd8c5ed commit 275d891

File tree

3 files changed

+21
-11
lines changed

3 files changed

+21
-11
lines changed

Diff for: compiler/src/dotty/tools/dotc/typer/Applications.scala

+9-4
Original file line numberDiff line numberDiff line change
@@ -945,12 +945,17 @@ trait Applications extends Compatibility {
945945
val app1 =
946946
if (!success || typedArgs.exists(_.tpe.isError)) app0.withType(UnspecifiedErrorType)
947947
else {
948-
if !sameSeq(args, orderedArgs)
949-
&& !isJavaAnnotConstr(methRef.symbol)
950-
&& !typedArgs.forall(isSafeArg)
951-
then
948+
if isJavaAnnotConstr(methRef.symbol) then
949+
// #19951 Make sure all arguments are NamedArgs for Java annotations
950+
if typedArgs.exists(!_.isInstanceOf[NamedArg]) then
951+
typedArgs = typedArgs.lazyZip(methType.asInstanceOf[MethodType].paramNames).map {
952+
case (arg: NamedArg, _) => arg
953+
case (arg, name) => NamedArg(name, arg)
954+
}
955+
else if !sameSeq(args, orderedArgs) && !typedArgs.forall(isSafeArg) then
952956
// need to lift arguments to maintain evaluation order in the
953957
// presence of argument reorderings.
958+
// (never do this for Java annotation constructors, hence the 'else if')
954959

955960
liftFun()
956961

Diff for: tests/run-macros/annot-arg-value-in-java.check

+6-6
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ new java.lang.SuppressWarnings(value = "a")
33
new java.lang.SuppressWarnings(value = "b")
44
new java.lang.SuppressWarnings(value = _root_.scala.Array.apply[java.lang.String]("c", "d")(scala.reflect.ClassTag.apply[java.lang.String](classOf[java.lang.String])))
55
JOtherTypes:
6-
new Annot(value = 1, _, _)
7-
new Annot(value = -2, _, _)
8-
new Annot(_, m = false, _)
9-
new Annot(_, m = true, _)
10-
new Annot(_, _, n = 1.1)
11-
new Annot(_, _, n = -2.1)
6+
new Annot(value = 1, m = _, n = _)
7+
new Annot(value = -2, m = _, n = _)
8+
new Annot(value = _, m = false, n = _)
9+
new Annot(value = _, m = true, n = _)
10+
new Annot(value = _, m = _, n = 1.1)
11+
new Annot(value = _, m = _, n = -2.1)

Diff for: tests/run-macros/annot-java-tree/AnnoMacro.scala

+6-1
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,17 @@ def checkSuppressWarningsImpl[T: Type](using Quotes): Expr[Unit] =
88
val sym = TypeRepr.of[T].typeSymbol
99
// Imitate what wartremover does, so we can avoid unintentionally breaking it:
1010
// https://github.com/wartremover/wartremover/blob/fb18e6eafe9a47823e04960aaf4ec7a9293719ef/core/src/main/scala-3/org/wartremover/WartUniverse.scala#L63-L77
11+
// We're intentionally breaking it in 3.5.x, though, with the addition of `NamedArg("value", ...)`
12+
// The previous implementation would be broken for cases where the user explicitly write `value = ...` anyway.
1113
val actualArgs = sym
1214
.getAnnotation(SuppressWarningsSymbol)
1315
.collect {
1416
case Apply(
1517
Select(_, "<init>"),
16-
Apply(Apply(_, Typed(Repeated(values, _), _) :: Nil), Apply(_, _ :: Nil) :: Nil) :: Nil
18+
NamedArg(
19+
"value",
20+
Apply(Apply(_, Typed(Repeated(values, _), _) :: Nil), Apply(_, _ :: Nil) :: Nil)
21+
) :: Nil
1722
) =>
1823
// "-Yexplicit-nulls"
1924
// https://github.com/wartremover/wartremover/issues/660

0 commit comments

Comments
 (0)