@@ -20,6 +20,7 @@ import mill.util.Jvm
2020
2121import os .Path
2222import scala .util .Try
23+ import scala .annotation .unused
2324
2425/**
2526 * Core configuration required to compile a single Java compilation target
@@ -108,6 +109,7 @@ trait JavaModule
108109 def testQuick (args : String * ): Command [(String , Seq [TestResult ])] = Task .Command (persistent = true ) {
109110 val quicktestFailedClassesLog = Task .dest / " quickTestFailedClasses.json"
110111 val transitiveCallGraphHashes0 = Task .dest / " transitiveCallGraphHashes0.json"
112+ val invalidatedClassNamesLog = Task .dest / " invalidatedClassNames.json"
111113
112114 val classFiles : Seq [os.Path ] = callGraphAnalysisClasspath()
113115 .flatMap(os.walk(_).filter(_.ext == " class" ))
@@ -120,7 +122,7 @@ trait JavaModule
120122 ignoreCall = (callSiteOpt, calledSig) => callGraphAnalysisIgnoreCalls(callSiteOpt, calledSig)
121123 )
122124 val testClasses = testForkGrouping()
123- val (quickTestClassLists, invalidClassNames ) = if (! os.exists(transitiveCallGraphHashes0)) {
125+ val (quickTestClassLists, invalidatedClassNames ) = if (! os.exists(transitiveCallGraphHashes0)) {
124126 // cannot calcuate invalid classes, so test all classes
125127 testClasses -> Set .empty[String ]
126128 } else {
@@ -133,15 +135,15 @@ trait JavaModule
133135 }.getOrElse(Seq .empty[String ]).toSet
134136 }
135137
136- val invalidClassNames = callAnalysis.calculateInvalidClassName {
138+ val invalidatedClassNames = callAnalysis.calculateInvalidatedClassNames {
137139 Some (upickle.default.read[Map [String , Int ]](os.read.stream(transitiveCallGraphHashes0)))
138140 }
139141
140- val testingClasses = invalidClassNames ++ failedTestClasses
142+ val testingClasses = invalidatedClassNames ++ failedTestClasses
141143
142144 testClasses
143145 .map(_.filter(testingClasses.contains))
144- .filter(_.nonEmpty) -> invalidClassNames
146+ .filter(_.nonEmpty) -> invalidatedClassNames
145147 }
146148
147149 // Clean up the directory for test runners
@@ -171,7 +173,7 @@ trait JavaModule
171173
172174 val results = testModuleUtil.runTests()
173175
174- val badTestClasses = results match {
176+ val badTestClasses = ( results match {
175177 case Result .Failure (_) =>
176178 // Consider all quick testing classes as failed
177179 quickTestClassLists.flatten
@@ -180,11 +182,11 @@ trait JavaModule
180182 results
181183 .filter(testResult => Set (" Error" , " Failure" ).contains(testResult.status))
182184 .map(_.fullyQualifiedName)
183- }
185+ }).distinct
184186
185- os.write.over(quicktestFailedClassesLog, upickle.default.write(badTestClasses.distinct ))
187+ os.write.over(quicktestFailedClassesLog, upickle.default.write(badTestClasses))
186188 os.write.over(transitiveCallGraphHashes0, upickle.default.write(callAnalysis.transitiveCallGraphHashes0))
187- os.write.over(Task .dest / " invalidClasses.json " , upickle.default.write(invalidClassNames ))
189+ os.write.over(invalidatedClassNamesLog , upickle.default.write(invalidatedClassNames ))
188190
189191 results match {
190192 case Result .Failure (errMsg) => Result .Failure (errMsg)
@@ -1486,47 +1488,9 @@ trait JavaModule
14861488
14871489 @ internal
14881490 protected def callGraphAnalysisIgnoreCalls (
1489- callSiteOpt : Option [mill.codesig.JvmModel .MethodDef ],
1490- calledSig : mill.codesig.JvmModel .MethodSig
1491- ): Boolean = {
1492- // We can ignore all calls to methods that look like Targets when traversing
1493- // the call graph. We can do this because we assume `def` Targets are pure,
1494- // and so any changes in their behavior will be picked up by the runtime build
1495- // graph evaluator without needing to be accounted for in the post-compile
1496- // bytecode callgraph analysis.
1497- def isSimpleTarget (desc : mill.codesig.JvmModel .Desc ) =
1498- (desc.ret.pretty == classOf [mill.define.Target [? ]].getName ||
1499- desc.ret.pretty == classOf [mill.define.Worker [? ]].getName) &&
1500- desc.args.isEmpty
1501-
1502- // We avoid ignoring method calls that are simple trait forwarders, because
1503- // we need the trait forwarders calls to be counted in order to wire up the
1504- // method definition that a Target is associated with during evaluation
1505- // (e.g. `myModuleObject.myTarget`) with its implementation that may be defined
1506- // somewhere else (e.g. `trait MyModuleTrait{ def myTarget }`). Only that one
1507- // step is necessary, after that the runtime build graph invalidation logic can
1508- // take over
1509- def isForwarderCallsiteOrLambda =
1510- callSiteOpt.nonEmpty && {
1511- val callSiteSig = callSiteOpt.get.sig
1512-
1513- (callSiteSig.name == (calledSig.name + " $" ) &&
1514- callSiteSig.static &&
1515- callSiteSig.desc.args.size == 1 )
1516- || (
1517- // In Scala 3, lambdas are implemented by private instance methods,
1518- // not static methods, so they fall through the crack of "isSimpleTarget".
1519- // Here make the assumption that a zero-arg lambda called from a simpleTarget,
1520- // should in fact be tracked. e.g. see `integration.invalidation[codesig-hello]`,
1521- // where the body of the `def foo` target is a zero-arg lambda i.e. the argument
1522- // of `Cacher.cachedTarget`.
1523- // To be more precise I think ideally we should capture more information in the signature
1524- isSimpleTarget(callSiteSig.desc) && calledSig.name.contains(" $anonfun" )
1525- )
1526- }
1527-
1528- isSimpleTarget(calledSig.desc) && ! isForwarderCallsiteOrLambda
1529- }
1491+ @ unused callSiteOpt : Option [mill.codesig.JvmModel .MethodDef ],
1492+ @ unused calledSig : mill.codesig.JvmModel .MethodSig
1493+ ): Boolean = false
15301494
15311495 @ internal
15321496 protected def callGraphAnalysisClasspath : Task [Seq [os.Path ]] = Task .Anon {
0 commit comments