Skip to content

Commit dbcf30f

Browse files
committed
Allow any applications in annotations
1 parent 7668120 commit dbcf30f

File tree

12 files changed

+128
-139
lines changed

12 files changed

+128
-139
lines changed

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 15 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,47 +1433,26 @@ trait Checking {
14331433
tree
14341434

14351435
private def checkAnnotArg(tree: Tree)(using Context): Unit =
1436-
def isTupleModule(sym: Symbol): Boolean =
1437-
ctx.definitions.isTupleClass(sym.companionClass)
1438-
1439-
def isFunctionAllowed(t: Tree): Boolean =
1436+
def valid(t: Tree): Boolean =
14401437
t match
1441-
case Select(qual, nme.apply) =>
1442-
qual.symbol == defn.ArrayModule
1443-
|| qual.symbol == defn.ClassTagModule // class tags are used as arguments to Array.apply
1444-
|| qual.symbol == defn.SymbolModule // used in Akka
1445-
|| qual.symbol == defn.JSSymbolModule // used in Scala.js
1446-
|| isTupleModule(qual.symbol)
1447-
case Select(New(clazz), nme.CONSTRUCTOR) => clazz.symbol.isAnnotation
1448-
case Apply(fun, _) => isFunctionAllowed(fun)
1449-
case TypeApply(fun, _) => isFunctionAllowed(fun)
1438+
case _ if t.tpe.isEffectivelySingleton => true
1439+
case Literal(_) => true
1440+
// `_` is used as placeholder for unspecified arguments of Java
1441+
// annotations. Example: tests/run/java-ann-super-class
1442+
case Ident(nme.WILDCARD) => true
1443+
case Apply(fun, args) => valid(fun) && args.forall(valid)
1444+
case TypeApply(fun, args) => valid(fun)
1445+
case SeqLiteral(elems, _) => elems.forall(valid)
1446+
case Typed(expr, _) => valid(expr)
1447+
case NamedArg(_, arg) => valid(arg)
1448+
case Splice(_) => true
1449+
case Hole(_, _, _, _) => true
14501450
case _ => false
1451-
1452-
def valid(t: Tree): Boolean =
1453-
t.tpe.isEffectivelySingleton
1454-
|| (
1455-
t match
1456-
case Literal(_) => true
1457-
// `_` is used as placeholder for unspecified arguments of Java
1458-
// annotations. Example: tests/run/java-ann-super-class
1459-
case Ident(nme.WILDCARD) => true
1460-
case Apply(fun, args) => isFunctionAllowed(fun) && args.forall(valid)
1461-
case TypeApply(fun, args) => isFunctionAllowed(fun)
1462-
// Support for `x.isInstanceOf[T]`. Probably not needed.
1463-
//case TypeApply(meth @ Select(arg, _), _) if meth.symbol == defn.Any_asInstanceOf => valid(arg)
1464-
case SeqLiteral(elems, _) => elems.forall(valid)
1465-
case Typed(expr, _) => valid(expr)
1466-
case NamedArg(_, arg) => valid(arg)
1467-
case Splice(_) => true
1468-
case Hole(_, _, _, _) => true
1469-
case _ => false
1470-
)
1471-
14721451
if !valid(tree) then
14731452
report.error(
14741453
i"""Implementation restriction: not a valid annotation argument.
1475-
| Argument: $tree
1476-
| Type: ${tree.tpe}""",
1454+
|Argument: $tree
1455+
|Type: ${tree.tpe}""",
14771456
tree.srcPos
14781457
)
14791458

tests/neg/annot-invalid.check

Lines changed: 43 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,48 @@
1-
-- Error: tests/neg/annot-invalid.scala:7:21 ---------------------------------------------------------------------------
2-
7 | val x1: Int @annot(n + 1) = 0 // error
3-
| ^^^^^
1+
-- Error: tests/neg/annot-invalid.scala:4:21 ---------------------------------------------------------------------------
2+
4 | val x1: Int @annot(new Object {}) = 0 // error
3+
| ^^^^^^^^^^^^^
44
| Implementation restriction: not a valid annotation argument.
5-
| Argument: n.+(1)
6-
| Type: Int
7-
-- Error: tests/neg/annot-invalid.scala:8:22 ---------------------------------------------------------------------------
8-
8 | val x2: Int @annot(f(2)) = 0 // error
9-
| ^^^^
5+
| Argument: {
6+
| final class $anon() extends Object() {}
7+
| new $anon():Object
8+
| }
9+
| Type: Object
10+
-- Error: tests/neg/annot-invalid.scala:5:21 ---------------------------------------------------------------------------
11+
5 | val x2: Int @annot({val x = 1}) = 0 // error
12+
| ^^^^^^^^^^^
1013
| Implementation restriction: not a valid annotation argument.
11-
| Argument: f(2)
12-
| Type: Unit
13-
-- Error: tests/neg/annot-invalid.scala:9:21 ---------------------------------------------------------------------------
14-
9 | val x3: Int @annot(throw new Error()) = 0 // error
15-
| ^^^^^^^^^^^^^^^^^
14+
| Argument: {
15+
| val x: Int = 1
16+
| ()
17+
| }
18+
| Type: Unit
19+
-- Error: tests/neg/annot-invalid.scala:6:21 ---------------------------------------------------------------------------
20+
6 | val x4: Int @annot((x: Int) => x) = 0 // error
21+
| ^^^^^^^^^^^^^
1622
| Implementation restriction: not a valid annotation argument.
17-
| Argument: throw new Error()
18-
| Type: Nothing
19-
-- Error: tests/neg/annot-invalid.scala:10:21 --------------------------------------------------------------------------
20-
10 | val x4: Int @annot((x: Int) => x) = 0 // error
21-
| ^^^^^^^^^^^^^
22-
| Implementation restriction: not a valid annotation argument.
23-
| Argument: {
24-
| def $anonfun(x: Int): Int = x
25-
| closure($anonfun)
26-
| }
27-
| Type: Int => Int
28-
-- Error: tests/neg/annot-invalid.scala:12:9 ---------------------------------------------------------------------------
29-
12 | @annot(n + 1) val y1: Int = 0 // error
30-
| ^^^^^
31-
| Implementation restriction: not a valid annotation argument.
32-
| Argument: n.+(1)
33-
| Type: Int
34-
-- Error: tests/neg/annot-invalid.scala:13:10 --------------------------------------------------------------------------
35-
13 | @annot(f(2)) val y2: Int = 0 // error
36-
| ^^^^
37-
| Implementation restriction: not a valid annotation argument.
38-
| Argument: f(2)
39-
| Type: Unit
40-
-- Error: tests/neg/annot-invalid.scala:14:9 ---------------------------------------------------------------------------
41-
14 | @annot(throw new Error()) val y3: Int = 0 // error
42-
| ^^^^^^^^^^^^^^^^^
43-
| Implementation restriction: not a valid annotation argument.
44-
| Argument: throw new Error()
45-
| Type: Nothing
46-
-- Error: tests/neg/annot-invalid.scala:15:9 ---------------------------------------------------------------------------
47-
15 | @annot((x: Int) => x) val y4: Int = 0 // error
23+
| Argument: (x: Int) => x
24+
| Type: Int => Int
25+
-- Error: tests/neg/annot-invalid.scala:8:9 ----------------------------------------------------------------------------
26+
8 | @annot(new Object {}) val y1: Int = 0 // error
27+
| ^^^^^^^^^^^^^
28+
| Implementation restriction: not a valid annotation argument.
29+
| Argument: {
30+
| final class $anon() extends Object() {}
31+
| new $anon():Object
32+
| }
33+
| Type: Object
34+
-- Error: tests/neg/annot-invalid.scala:9:9 ----------------------------------------------------------------------------
35+
9 | @annot({val x = 1}) val y2: Int = 0 // error
36+
| ^^^^^^^^^^^
37+
| Implementation restriction: not a valid annotation argument.
38+
| Argument: {
39+
| val x: Int = 1
40+
| ()
41+
| }
42+
| Type: Unit
43+
-- Error: tests/neg/annot-invalid.scala:10:9 ---------------------------------------------------------------------------
44+
10 | @annot((x: Int) => x) val y4: Int = 0 // error
4845
| ^^^^^^^^^^^^^
4946
| Implementation restriction: not a valid annotation argument.
50-
| Argument: {
51-
| def $anonfun(x: Int): Int = x
52-
| closure($anonfun)
53-
| }
54-
| Type: Int => Int
47+
| Argument: (x: Int) => x
48+
| Type: Int => Int

tests/neg/annot-invalid.scala

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
11
class annot[T](arg: T) extends scala.annotation.Annotation
22

33
def main =
4-
val n: Int = 0
5-
def f(x: Any): Unit = ()
6-
7-
val x1: Int @annot(n + 1) = 0 // error
8-
val x2: Int @annot(f(2)) = 0 // error
9-
val x3: Int @annot(throw new Error()) = 0 // error
4+
val x1: Int @annot(new Object {}) = 0 // error
5+
val x2: Int @annot({val x = 1}) = 0 // error
106
val x4: Int @annot((x: Int) => x) = 0 // error
117

12-
@annot(n + 1) val y1: Int = 0 // error
13-
@annot(f(2)) val y2: Int = 0 // error
14-
@annot(throw new Error()) val y3: Int = 0 // error
8+
@annot(new Object {}) val y1: Int = 0 // error
9+
@annot({val x = 1}) val y2: Int = 0 // error
1510
@annot((x: Int) => x) val y4: Int = 0 // error
1611

1712
()

tests/neg/nowarn.check

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,22 @@
55
| its body in a block; no exceptions are handled.
66
|
77
| longer explanation available when compiling with `-explain`
8-
-- [E002] Syntax Warning: tests/neg/nowarn.scala:22:25 -----------------------------------------------------------------
9-
22 |@nowarn(o.inl) def t2d = try 1 // two warnings (`inl` is not a compile-time constant)
8+
-- [E002] Syntax Warning: tests/neg/nowarn.scala:25:25 -----------------------------------------------------------------
9+
25 |@nowarn(o.inl) def t2d = try 1 // two warnings (`inl` is not a compile-time constant)
1010
| ^^^^^
1111
| A try without catch or finally is equivalent to putting
1212
| its body in a block; no exceptions are handled.
1313
|
1414
| longer explanation available when compiling with `-explain`
15-
-- [E002] Syntax Warning: tests/neg/nowarn.scala:30:26 -----------------------------------------------------------------
16-
30 |@nowarn("id=1") def t4d = try 1 // error and warning (unused nowarn, wrong id)
15+
-- [E002] Syntax Warning: tests/neg/nowarn.scala:33:26 -----------------------------------------------------------------
16+
33 |@nowarn("id=1") def t4d = try 1 // error and warning (unused nowarn, wrong id)
1717
| ^^^^^
1818
| A try without catch or finally is equivalent to putting
1919
| its body in a block; no exceptions are handled.
2020
|
2121
| longer explanation available when compiling with `-explain`
22-
-- [E002] Syntax Warning: tests/neg/nowarn.scala:32:28 -----------------------------------------------------------------
23-
32 |@nowarn("verbose") def t5 = try 1 // warning with details
22+
-- [E002] Syntax Warning: tests/neg/nowarn.scala:35:28 -----------------------------------------------------------------
23+
35 |@nowarn("verbose") def t5 = try 1 // warning with details
2424
| ^^^^^
2525
| A try without catch or finally is equivalent to putting
2626
| its body in a block; no exceptions are handled.
@@ -40,61 +40,71 @@ Matching filters for @nowarn or -Wconf:
4040
| ^^^^^^
4141
| Invalid message filter
4242
| unknown filter: wat?
43-
-- Warning: tests/neg/nowarn.scala:22:10 -------------------------------------------------------------------------------
44-
22 |@nowarn(o.inl) def t2d = try 1 // two warnings (`inl` is not a compile-time constant)
43+
-- [E129] Potential Issue Warning: tests/neg/nowarn.scala:18:12 --------------------------------------------------------
44+
18 |def t2a = { 1; 2 } // warning (invalid nowarn doesn't silence)
45+
| ^
46+
| A pure expression does nothing in statement position
47+
|
48+
| longer explanation available when compiling with `-explain`
49+
-- Warning: tests/neg/nowarn.scala:17:8 --------------------------------------------------------------------------------
50+
17 |@nowarn(t1a.toString) // warning (typer, argument not a compile-time constant)
51+
| ^^^^^^^^^^^^
52+
| filter needs to be a compile-time constant string
53+
-- Warning: tests/neg/nowarn.scala:25:10 -------------------------------------------------------------------------------
54+
25 |@nowarn(o.inl) def t2d = try 1 // two warnings (`inl` is not a compile-time constant)
4555
| ^^^^^
4656
| filter needs to be a compile-time constant string
47-
-- Deprecation Warning: tests/neg/nowarn.scala:36:10 -------------------------------------------------------------------
48-
36 |def t6a = f // warning (refchecks, deprecation)
57+
-- Deprecation Warning: tests/neg/nowarn.scala:39:10 -------------------------------------------------------------------
58+
39 |def t6a = f // warning (refchecks, deprecation)
4959
| ^
5060
| method f is deprecated
51-
-- Deprecation Warning: tests/neg/nowarn.scala:39:30 -------------------------------------------------------------------
52-
39 |@nowarn("msg=fish") def t6d = f // error (unused nowarn), warning (deprecation)
61+
-- Deprecation Warning: tests/neg/nowarn.scala:42:30 -------------------------------------------------------------------
62+
42 |@nowarn("msg=fish") def t6d = f // error (unused nowarn), warning (deprecation)
5363
| ^
5464
| method f is deprecated
55-
-- Deprecation Warning: tests/neg/nowarn.scala:46:10 -------------------------------------------------------------------
56-
46 |def t7c = f // warning (deprecation)
65+
-- Deprecation Warning: tests/neg/nowarn.scala:49:10 -------------------------------------------------------------------
66+
49 |def t7c = f // warning (deprecation)
5767
| ^
5868
| method f is deprecated
59-
-- [E092] Pattern Match Unchecked Warning: tests/neg/nowarn.scala:52:7 -------------------------------------------------
60-
52 | case _: List[Int] => 0 // warning (patmat, unchecked)
69+
-- [E092] Pattern Match Unchecked Warning: tests/neg/nowarn.scala:55:7 -------------------------------------------------
70+
55 | case _: List[Int] => 0 // warning (patmat, unchecked)
6171
| ^
6272
|the type test for List[Int] cannot be checked at runtime because its type arguments can't be determined from Any
6373
|
6474
| longer explanation available when compiling with `-explain`
65-
-- Error: tests/neg/nowarn.scala:30:1 ----------------------------------------------------------------------------------
66-
30 |@nowarn("id=1") def t4d = try 1 // error and warning (unused nowarn, wrong id)
75+
-- Error: tests/neg/nowarn.scala:33:1 ----------------------------------------------------------------------------------
76+
33 |@nowarn("id=1") def t4d = try 1 // error and warning (unused nowarn, wrong id)
6777
|^^^^^^^^^^^^^^^
6878
|@nowarn annotation does not suppress any warnings
69-
-- Error: tests/neg/nowarn.scala:39:1 ----------------------------------------------------------------------------------
70-
39 |@nowarn("msg=fish") def t6d = f // error (unused nowarn), warning (deprecation)
79+
-- Error: tests/neg/nowarn.scala:42:1 ----------------------------------------------------------------------------------
80+
42 |@nowarn("msg=fish") def t6d = f // error (unused nowarn), warning (deprecation)
7181
|^^^^^^^^^^^^^^^^^^^
7282
|@nowarn annotation does not suppress any warnings
73-
-- Error: tests/neg/nowarn.scala:47:5 ----------------------------------------------------------------------------------
74-
47 | : @nowarn("msg=fish") // error (unused nowarn)
83+
-- Error: tests/neg/nowarn.scala:50:5 ----------------------------------------------------------------------------------
84+
50 | : @nowarn("msg=fish") // error (unused nowarn)
7585
| ^^^^^^^^^^^^^^^^^^^
7686
| @nowarn annotation does not suppress any warnings
77-
-- Error: tests/neg/nowarn.scala:59:0 ----------------------------------------------------------------------------------
78-
59 |@nowarn def t9a = { 1: @nowarn; 2 } // error (outer @nowarn is unused)
87+
-- Error: tests/neg/nowarn.scala:62:0 ----------------------------------------------------------------------------------
88+
62 |@nowarn def t9a = { 1: @nowarn; 2 } // error (outer @nowarn is unused)
7989
|^^^^^^^
8090
|@nowarn annotation does not suppress any warnings
81-
-- Error: tests/neg/nowarn.scala:60:27 ---------------------------------------------------------------------------------
82-
60 |@nowarn def t9b = { 1: Int @nowarn; 2 } // error (inner @nowarn is unused, it covers the type, not the expression)
91+
-- Error: tests/neg/nowarn.scala:63:27 ---------------------------------------------------------------------------------
92+
63 |@nowarn def t9b = { 1: Int @nowarn; 2 } // error (inner @nowarn is unused, it covers the type, not the expression)
8393
| ^^^^^^^
8494
| @nowarn annotation does not suppress any warnings
85-
-- Error: tests/neg/nowarn.scala:65:0 ----------------------------------------------------------------------------------
86-
65 |@nowarn @ann(f) def t10b = 0 // error (unused nowarn)
95+
-- Error: tests/neg/nowarn.scala:68:0 ----------------------------------------------------------------------------------
96+
68 |@nowarn @ann(f) def t10b = 0 // error (unused nowarn)
8797
|^^^^^^^
8898
|@nowarn annotation does not suppress any warnings
89-
-- Error: tests/neg/nowarn.scala:66:8 ----------------------------------------------------------------------------------
90-
66 |@ann(f: @nowarn) def t10c = 0 // error (unused nowarn), should be silent
99+
-- Error: tests/neg/nowarn.scala:69:8 ----------------------------------------------------------------------------------
100+
69 |@ann(f: @nowarn) def t10c = 0 // error (unused nowarn), should be silent
91101
| ^^^^^^^
92102
| @nowarn annotation does not suppress any warnings
93-
-- Error: tests/neg/nowarn.scala:69:0 ----------------------------------------------------------------------------------
94-
69 |@nowarn class I1a { // error (unused nowarn)
103+
-- Error: tests/neg/nowarn.scala:72:0 ----------------------------------------------------------------------------------
104+
72 |@nowarn class I1a { // error (unused nowarn)
95105
|^^^^^^^
96106
|@nowarn annotation does not suppress any warnings
97-
-- Error: tests/neg/nowarn.scala:74:0 ----------------------------------------------------------------------------------
98-
74 |@nowarn class I1b { // error (unused nowarn)
107+
-- Error: tests/neg/nowarn.scala:77:0 ----------------------------------------------------------------------------------
108+
77 |@nowarn class I1b { // error (unused nowarn)
99109
|^^^^^^^
100110
|@nowarn annotation does not suppress any warnings

tests/neg/nowarn.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ def t1a = try 1 // warning (parser)
1414
@nowarn("wat?") // warning (typer, invalid filter)
1515
def t2 = { 1; 2 } // warning (the invalid nowarn doesn't silence anything)
1616

17+
@nowarn(t1a.toString) // warning (typer, argument not a compile-time constant)
18+
def t2a = { 1; 2 } // warning (invalid nowarn doesn't silence)
19+
1720
object o:
1821
final val const = "msg=try"
1922
inline def inl = "msg=try"

tests/neg/serialversionuid-not-const.scala

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
@SerialVersionUID(13l.toLong) class C1 extends Serializable // OK because toLong is constant-folded
22
@SerialVersionUID(13l) class C2 extends Serializable // OK
3-
4-
//@SerialVersionUID(13.asInstanceOf[Long]) class C3 extends Serializable
5-
//now catched in typer already: not a valid annotation argument
6-
3+
@SerialVersionUID(13.asInstanceOf[Long]) class C3 extends Serializable // error
74
@SerialVersionUID(Test.bippy) class C4 extends Serializable // error
85

96
object Test {

tests/pos/annot-valid.scala

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
class annot[T](arg: T) extends scala.annotation.Annotation
22

33
def main =
4-
val n: Int = ???
4+
val n: Int = 0
55
def f(x: Any): Unit = ()
66

77
val x1: Int @annot(42) = 0
@@ -14,6 +14,10 @@ def main =
1414
val x8: Int @annot(((1,2),3)) = 0
1515
val x9: Int @annot(((1,2),(3,4))) = 0
1616
val x10: Int @annot(Symbol("hello")) = 0
17+
val x11: Int @annot(n + 1) = 0
18+
val x12: Int @annot(f(2)) = 0
19+
val x13: Int @annot(throw new Error()) = 0
20+
val x14: Int @annot(42: Double) = 0
1721

1822
@annot(42) val y1: Int = 0
1923
@annot("hello") val y2: Int = 0
@@ -25,5 +29,9 @@ def main =
2529
@annot(((1,2),3)) val y8: Int = 0
2630
@annot(((1,2),(3,4))) val y9: Int = 0
2731
@annot(Symbol("hello")) val y10: Int = 0
32+
@annot(n + 1) val y11: Int = 0
33+
@annot(f(2)) val y12: Int = 0
34+
@annot(throw new Error()) val y13: Int = 0
35+
@annot(42: Double) val y14: Int = 0
2836

2937
()

tests/neg/t1942.scala renamed to tests/pos/t1942/A_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ class ann(x: Int) extends annotation.StaticAnnotation
77

88
class t {
99
val a = new A
10-
@ann(a.foo(1)) def bar = 1 // error: not a valid annotation
10+
@ann(a.foo(1)) def bar = 1
1111
}

tests/pos/t1942/Test_2.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class Test {
2+
println(new t)
3+
}

0 commit comments

Comments
 (0)