Skip to content

Commit 3d4af20

Browse files
Merge pull request #14944 from dotty-staging/add-experimental-checks
Add a test to track @experimental definitions
2 parents c93a237 + 3f642da commit 3d4af20

File tree

1 file changed

+129
-0
lines changed

1 file changed

+129
-0
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import scala.quoted.*
2+
import scala.tasty.inspector.*
3+
4+
val experimentalDefinitionInLibrary = Set(
5+
6+
// README
7+
// - Definitions should be grouped under a language feature or API
8+
// - API definitions that must be stabilized at the same time should be added in the same line
9+
// - Language definitions are assumed to be stabilized all at once unless stated otherwise
10+
11+
12+
//// New feature: Safe Exceptions
13+
// Can be stabilized when safe exeptions language feature is stabilized.
14+
"scala.CanThrow",
15+
"scala.unsafeExceptions", "scala.unsafeExceptions$",
16+
"scala.runtime.$throws$package$.$throws",
17+
18+
//// New feature: Tupled Functions
19+
// Can be stabilized when language feature is stabilized.
20+
// Needs user feedback.
21+
// Needs generalization to polymorphic types (at least proof of concept that shows that that design is compatible).
22+
"scala.runtime.TupledFunctions",
23+
"scala.runtime.TupledFunctions$",
24+
"scala.util.TupledFunction",
25+
"scala.util.TupledFunction$",
26+
27+
//// New feature: main annotation generalization
28+
// Can be stabilized when language feature is stabilized.
29+
// Needs user feedback.
30+
// Should argGetter/varargGetter be simplified?
31+
// Should we have better support for main annotation macros?
32+
"scala.annotation.MainAnnotation",
33+
"scala.annotation.MainAnnotation$",
34+
35+
//// New APIs: compiletime.ops
36+
// Can be stabilized in 3.3.0 or later.
37+
// Needs user feedback
38+
"scala.compiletime.ops.any$.IsConst",
39+
"scala.compiletime.ops.any$.ToString",
40+
"scala.compiletime.ops.double", "scala.compiletime.ops.double$",
41+
"scala.compiletime.ops.float",
42+
"scala.compiletime.ops.float$",
43+
"scala.compiletime.ops.int$.NumberOfLeadingZeros",
44+
"scala.compiletime.ops.int$.ToDouble",
45+
"scala.compiletime.ops.int$.ToFloat",
46+
"scala.compiletime.ops.int$.ToLong",
47+
"scala.compiletime.ops.long", "scala.compiletime.ops.long$",
48+
"scala.compiletime.ops.string$.Length",
49+
"scala.compiletime.ops.string$.Matches",
50+
"scala.compiletime.ops.string$.Substring",
51+
52+
//// New APIs: Mirror
53+
// Can be stabilized in 3.2.0 or later.
54+
"scala.deriving.Mirror$.fromTuple", // Probably for 3.2.0
55+
"scala.deriving.Mirror$.fromProductTyped", // This API is a bit convoluted. We may need some more feedback before we can stabilize it.
56+
57+
//// New APIs: Tuples
58+
// Should be stabilized in 3.2.0.
59+
"scala.Tuple.:*", "scala.Tuple$.Append", "scala.runtime.Tuples$.append",
60+
"scala.NonEmptyTuple.init", "scala.Tuple$.Init", "scala.runtime.Tuples$.init",
61+
"scala.Tuple$.Last", "scala.NonEmptyTuple.last", "scala.runtime.Tuples$.last",
62+
63+
//// New APIs: Quotes
64+
// Should be stabilized in 3.2.0.
65+
"scala.quoted.Quotes.reflectModule.AppliedTypeModule.apply",
66+
"scala.quoted.Quotes.reflectModule.SymbolMethods.asQuotes",
67+
"scala.quoted.Quotes.reflectModule.SymbolMethods.termRef",
68+
"scala.quoted.Quotes.reflectModule.SymbolMethods.typeRef",
69+
"scala.quoted.Quotes.reflectModule.TypeReprMethods.substituteTypes",
70+
"scala.quoted.Quotes.reflectModule.TypeReprMethods.typeArgs",
71+
"scala.quoted.Quotes.reflectModule.TypeTreeModule.ref",
72+
// Can be stabilized in 3.2.0 (unsure) or later
73+
"scala.quoted.Quotes.reflectModule.CompilationInfoModule.XmacroSettings",
74+
// Cant be stabilized yet.
75+
// Need newClass variant that can add constructor parameters.
76+
// Need experimental annotation macros to check that design works.
77+
"scala.quoted.Quotes.reflectModule.ClassDefModule.apply",
78+
"scala.quoted.Quotes.reflectModule.SymbolModule.newClass",
79+
)
80+
81+
82+
@main def Test = {
83+
val inspector = new Inspector {
84+
def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit = {
85+
import quotes.reflect.*
86+
val experimentalAnnot = Symbol.requiredClass("scala.annotation.experimental")
87+
object AccumulateExperimentalDefs extends TreeAccumulator[Set[Symbol]]:
88+
def foldTree(expDefs: Set[Symbol], tree: Tree)(owner: Symbol): Set[Symbol] =
89+
tree match
90+
case tree: Definition if tree.symbol.hasAnnotation(experimentalAnnot) => foldOverTree(expDefs + tree.symbol, tree)(owner)
91+
case _ => foldOverTree(expDefs, tree)(owner)
92+
93+
val experimentalDefinitionsSyms = tastys.foldLeft(Set.empty[Symbol]) { (acc, tasty) =>
94+
AccumulateExperimentalDefs.foldTree(acc, tasty.ast)(Symbol.spliceOwner)
95+
}
96+
val experimentalDefinitions = experimentalDefinitionsSyms.map(_.fullName)
97+
val missingFromList = experimentalDefinitions -- experimentalDefinitionInLibrary
98+
val missingInLibrary = experimentalDefinitionInLibrary -- experimentalDefinitions
99+
assert(missingFromList.isEmpty,
100+
s"""Failed @experimental definitions check
101+
|
102+
|Found @experimental definition in library not listed:
103+
|${missingFromList.toSeq.sorted.mkString("\n")}
104+
|
105+
|If added new experimental defintions to the library, add them to the list in tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala
106+
|
107+
|Test only: sbt "scala3-bootstrapped/testCompilation tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala"
108+
|""".stripMargin
109+
)
110+
assert(missingInLibrary.isEmpty,
111+
s"""Failed @experimental definitions check
112+
|
113+
|Listed @experimental definition was not found in the library
114+
|${missingInLibrary.toSeq.sorted.mkString("\n")}
115+
|
116+
|If experimental definition was removed or stabilized, remove from the list in tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala
117+
|
118+
|Test only: sbt "scala3-bootstrapped/testCompilation tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala"
119+
|""".stripMargin
120+
)
121+
}
122+
}
123+
124+
// Artefact of the current test infrastructure
125+
// TODO improve infrastructure to avoid needing this code on each test
126+
val libJarClasspath = dotty.tools.dotc.util.ClasspathFromClassloader(this.getClass.getClassLoader).split(java.io.File.pathSeparator).find(x => x.contains("scala3-library-bootstrapped") && x.endsWith(".jar")).get
127+
128+
TastyInspector.inspectTastyFilesInJar(libJarClasspath)(inspector)
129+
}

0 commit comments

Comments
 (0)