Skip to content

Commit 137be13

Browse files
Backport "emit generatedNonLocalClass in backend when callback is not enabled" to 3.5.0 (#21209)
Backports #21186 to 3.5.0-RC5
2 parents 97fc22c + 7342816 commit 137be13

File tree

5 files changed

+112
-44
lines changed

5 files changed

+112
-44
lines changed

Diff for: compiler/src/dotty/tools/backend/jvm/CodeGen.scala

+9-2
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,15 @@ class CodeGen(val int: DottyBackendInterface, val primitives: DottyPrimitives)(
133133
if (ctx.compilerCallback != null)
134134
ctx.compilerCallback.onClassGenerated(sourceFile, convertAbstractFile(clsFile), className)
135135

136-
if isLocal then
137-
ctx.withIncCallback(_.generatedLocalClass(sourceFile, clsFile.jpath))
136+
ctx.withIncCallback: cb =>
137+
if isLocal then
138+
cb.generatedLocalClass(sourceFile, clsFile.jpath)
139+
else if !cb.enabled() then
140+
// callback is not enabled, so nonLocalClasses were not reported in ExtractAPI
141+
val fullClassName = atPhase(sbtExtractDependenciesPhase) {
142+
ExtractDependencies.classNameAsString(claszSymbol)
143+
}
144+
cb.generatedNonLocalClass(sourceFile, clsFile.jpath, className, fullClassName)
138145
}
139146
}
140147

Diff for: sbt-bridge/test/xsbt/ExtractUsedNamesSpecification.scala

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package xsbt
22

33
import xsbti.UseScope
4-
import ScalaCompilerForUnitTesting.Callbacks
54

65
import org.junit.{ Test, Ignore }
76
import org.junit.Assert._
@@ -227,9 +226,9 @@ class ExtractUsedNamesSpecification {
227226

228227
def findPatMatUsages(in: String): Set[String] = {
229228
val compilerForTesting = new ScalaCompilerForUnitTesting
230-
val (_, Callbacks(callback, _)) =
229+
val output =
231230
compilerForTesting.compileSrcs(List(List(sealedClass, in)))
232-
val clientNames = callback.usedNamesAndScopes.view.filterKeys(!_.startsWith("base."))
231+
val clientNames = output.analysis.usedNamesAndScopes.view.filterKeys(!_.startsWith("base."))
233232

234233
val names: Set[String] = clientNames.flatMap {
235234
case (_, usages) =>

Diff for: sbt-bridge/test/xsbt/ProductsSpecification.scala

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package xsbt
2+
3+
import org.junit.Assert.*
4+
import org.junit.Ignore
5+
import org.junit.Test
6+
7+
import java.io.File
8+
import java.nio.file.Path
9+
import java.nio.file.Paths
10+
11+
class ProductsSpecification {
12+
13+
@Test
14+
def extractNonLocalClassesNoInc = {
15+
val src =
16+
"""package example
17+
|
18+
|class A {
19+
| class B
20+
| def foo =
21+
| class C
22+
|}""".stripMargin
23+
val output = compiler.compileSrcsNoInc(src)
24+
val srcFile = output.srcFiles.head
25+
val (srcNames, binaryNames) = output.analysis.classNames(srcFile).unzip // non local class names
26+
27+
assertFalse(output.analysis.enabled()) // inc phases are disabled
28+
assertTrue(output.analysis.apis.isEmpty) // extract-api did not run
29+
assertTrue(output.analysis.usedNamesAndScopes.isEmpty) // extract-dependencies did not run
30+
31+
// note that local class C is not included, classNames only records non local classes
32+
val expectedBinary = Set("example.A", "example.A$B")
33+
assertEquals(expectedBinary, binaryNames.toSet)
34+
35+
// note that local class C is not included, classNames only records non local classes
36+
val expectedSrc = Set("example.A", "example.A.B")
37+
assertEquals(expectedSrc, srcNames.toSet)
38+
}
39+
40+
private def compiler = new ScalaCompilerForUnitTesting
41+
}

Diff for: sbt-bridge/test/xsbt/ScalaCompilerForUnitTesting.scala

+56-39
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package xsbt
33

44
import xsbti.compile.{CompileProgress, SingleOutput}
55
import java.io.File
6+
import java.nio.file.Path
67
import xsbti._
78
import sbt.io.IO
89
import xsbti.api.{ ClassLike, Def, DependencyContext }
@@ -15,6 +16,8 @@ import dotty.tools.xsbt.CompilerBridge
1516
import TestCallback.ExtractedClassDependencies
1617
import ScalaCompilerForUnitTesting.Callbacks
1718

19+
case class CompileOutput(srcFiles: Seq[VirtualFileRef], classesOutput: Path, analysis: TestCallback, progress: TestCompileProgress)
20+
1821
object ScalaCompilerForUnitTesting:
1922
case class Callbacks(analysis: TestCallback, progress: TestCompileProgress)
2023

@@ -25,38 +28,33 @@ object ScalaCompilerForUnitTesting:
2528
class ScalaCompilerForUnitTesting {
2629

2730
def extractEnteredPhases(srcs: String*): Seq[List[String]] = {
28-
val (tempSrcFiles, Callbacks(_, testProgress)) = compileSrcs(srcs*)
29-
val run = testProgress.runs.head
30-
tempSrcFiles.map(src => run.unitPhases(src.id))
31+
val output = compileSrcs(srcs*)
32+
val run = output.progress.runs.head
33+
output.srcFiles.map(src => run.unitPhases(src.id))
3134
}
3235

33-
def extractTotal(srcs: String*)(extraSourcePath: String*): Int = {
34-
val (tempSrcFiles, Callbacks(_, testProgress)) = compileSrcs(List(srcs.toList), extraSourcePath.toList)
35-
val run = testProgress.runs.head
36-
run.total
37-
}
36+
def extractTotal(srcs: String*)(extraSourcePath: String*): Int =
37+
compileSrcs(List(srcs.toList), extraSourcePath.toList).progress.runs.head.total
3838

39-
def extractProgressPhases(srcs: String*): List[String] = {
40-
val (_, Callbacks(_, testProgress)) = compileSrcs(srcs*)
41-
testProgress.runs.head.phases
42-
}
39+
def extractProgressPhases(srcs: String*): List[String] =
40+
compileSrcs(srcs*).progress.runs.head.phases
4341

4442
/**
4543
* Compiles given source code using Scala compiler and returns API representation
4644
* extracted by ExtractAPI class.
4745
*/
4846
def extractApiFromSrc(src: String): Seq[ClassLike] = {
49-
val (Seq(tempSrcFile), Callbacks(analysisCallback, _)) = compileSrcs(src)
50-
analysisCallback.apis(tempSrcFile)
47+
val output = compileSrcs(src)
48+
output.analysis.apis(output.srcFiles.head)
5149
}
5250

5351
/**
5452
* Compiles given source code using Scala compiler and returns API representation
5553
* extracted by ExtractAPI class.
5654
*/
5755
def extractApisFromSrcs(srcs: List[String]*): Seq[Seq[ClassLike]] = {
58-
val (tempSrcFiles, Callbacks(analysisCallback, _)) = compileSrcs(srcs.toList)
59-
tempSrcFiles.map(analysisCallback.apis)
56+
val output = compileSrcs(srcs.toList)
57+
output.srcFiles.map(output.analysis.apis)
6058
}
6159

6260
/**
@@ -73,15 +71,16 @@ class ScalaCompilerForUnitTesting {
7371
assertDefaultScope: Boolean = true
7472
): Map[String, Set[String]] = {
7573
// we drop temp src file corresponding to the definition src file
76-
val (Seq(_, tempSrcFile), Callbacks(analysisCallback, _)) = compileSrcs(definitionSrc, actualSrc)
74+
val output = compileSrcs(definitionSrc, actualSrc)
75+
val analysis = output.analysis
7776

7877
if (assertDefaultScope) for {
79-
(className, used) <- analysisCallback.usedNamesAndScopes
80-
analysisCallback.TestUsedName(name, scopes) <- used
78+
(className, used) <- analysis.usedNamesAndScopes
79+
analysis.TestUsedName(name, scopes) <- used
8180
} assert(scopes.size() == 1 && scopes.contains(UseScope.Default), s"$className uses $name in $scopes")
8281

83-
val classesInActualSrc = analysisCallback.classNames(tempSrcFile).map(_._1)
84-
classesInActualSrc.map(className => className -> analysisCallback.usedNames(className)).toMap
82+
val classesInActualSrc = analysis.classNames(output.srcFiles.head).map(_._1)
83+
classesInActualSrc.map(className => className -> analysis.usedNames(className)).toMap
8584
}
8685

8786
/**
@@ -91,11 +90,11 @@ class ScalaCompilerForUnitTesting {
9190
* Only the names used in the last src file are returned.
9291
*/
9392
def extractUsedNamesFromSrc(sources: String*): Map[String, Set[String]] = {
94-
val (srcFiles, Callbacks(analysisCallback, _)) = compileSrcs(sources*)
95-
srcFiles
93+
val output = compileSrcs(sources*)
94+
output.srcFiles
9695
.map { srcFile =>
97-
val classesInSrc = analysisCallback.classNames(srcFile).map(_._1)
98-
classesInSrc.map(className => className -> analysisCallback.usedNames(className)).toMap
96+
val classesInSrc = output.analysis.classNames(srcFile).map(_._1)
97+
classesInSrc.map(className => className -> output.analysis.usedNames(className)).toMap
9998
}
10099
.reduce(_ ++ _)
101100
}
@@ -113,15 +112,15 @@ class ScalaCompilerForUnitTesting {
113112
* file system-independent way of testing dependencies between source code "files".
114113
*/
115114
def extractDependenciesFromSrcs(srcs: List[List[String]]): ExtractedClassDependencies = {
116-
val (_, Callbacks(testCallback, _)) = compileSrcs(srcs)
115+
val analysis = compileSrcs(srcs).analysis
117116

118-
val memberRefDeps = testCallback.classDependencies collect {
117+
val memberRefDeps = analysis.classDependencies collect {
119118
case (target, src, DependencyByMemberRef) => (src, target)
120119
}
121-
val inheritanceDeps = testCallback.classDependencies collect {
120+
val inheritanceDeps = analysis.classDependencies collect {
122121
case (target, src, DependencyByInheritance) => (src, target)
123122
}
124-
val localInheritanceDeps = testCallback.classDependencies collect {
123+
val localInheritanceDeps = analysis.classDependencies collect {
125124
case (target, src, LocalDependencyByInheritance) => (src, target)
126125
}
127126
ExtractedClassDependencies.fromPairs(memberRefDeps, inheritanceDeps, localInheritanceDeps)
@@ -142,12 +141,24 @@ class ScalaCompilerForUnitTesting {
142141
* The sequence of temporary files corresponding to passed snippets and analysis
143142
* callback is returned as a result.
144143
*/
145-
def compileSrcs(groupedSrcs: List[List[String]], sourcePath: List[String] = Nil): (Seq[VirtualFile], Callbacks) = {
144+
def compileSrcs(groupedSrcs: List[List[String]], sourcePath: List[String] = Nil, compileToJar: Boolean = false, incEnabled: Boolean = true): CompileOutput = {
146145
val temp = IO.createTemporaryDirectory
147-
val analysisCallback = new TestCallback
146+
val (forceSbtArgs, analysisCallback) =
147+
if (incEnabled)
148+
(Seq("-Yforce-sbt-phases"), new TestCallback)
149+
else
150+
(Seq.empty, new TestCallbackNoInc)
148151
val testProgress = new TestCompileProgress
149-
val classesDir = new File(temp, "classes")
150-
classesDir.mkdir()
152+
val classesOutput =
153+
if (compileToJar) {
154+
val jar = new File(temp, "classes.jar")
155+
jar.createNewFile()
156+
jar
157+
} else {
158+
val dir = new File(temp, "classes")
159+
dir.mkdir()
160+
dir
161+
}
151162

152163
val bridge = new CompilerBridge
153164

@@ -164,16 +175,16 @@ class ScalaCompilerForUnitTesting {
164175
}
165176

166177
val virtualSrcFiles = srcFiles.toArray
167-
val classesDirPath = classesDir.getAbsolutePath.toString
178+
val classesOutputPath = classesOutput.getAbsolutePath()
168179
val output = new SingleOutput:
169-
def getOutputDirectory() = classesDir
180+
def getOutputDirectory() = classesOutput
170181

171182
val maybeSourcePath = if extraFiles.isEmpty then Nil else List("-sourcepath", temp.getAbsolutePath.toString)
172183

173184
bridge.run(
174185
virtualSrcFiles,
175186
new TestDependencyChanges,
176-
Array("-Yforce-sbt-phases", "-classpath", classesDirPath, "-usejavacp", "-d", classesDirPath) ++ maybeSourcePath,
187+
(forceSbtArgs ++: Array("-classpath", classesOutputPath, "-usejavacp", "-d", classesOutputPath)) ++ maybeSourcePath,
177188
output,
178189
analysisCallback,
179190
new TestReporter,
@@ -185,17 +196,23 @@ class ScalaCompilerForUnitTesting {
185196

186197
srcFiles
187198
}
188-
(files.flatten.toSeq, Callbacks(analysisCallback, testProgress))
199+
CompileOutput(files.flatten.toSeq, classesOutput.toPath, analysisCallback, testProgress)
189200
}
190201

191-
def compileSrcs(srcs: String*): (Seq[VirtualFile], Callbacks) = {
202+
def compileSrcs(srcs: String*): CompileOutput = {
192203
compileSrcs(List(srcs.toList))
193204
}
194205

206+
def compileSrcsNoInc(srcs: String*): CompileOutput = {
207+
compileSrcs(List(srcs.toList), incEnabled = false)
208+
}
209+
210+
def compileSrcsToJar(srcs: String*): CompileOutput =
211+
compileSrcs(List(srcs.toList), compileToJar = true)
212+
195213
private def prepareSrcFile(baseDir: File, fileName: String, src: String): VirtualFile = {
196214
val srcFile = new File(baseDir, fileName)
197215
IO.write(srcFile, src)
198216
new TestVirtualFile(srcFile.toPath)
199217
}
200218
}
201-

Diff for: sbt-bridge/test/xsbti/TestCallback.scala

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ import DependencyContext._
1111
import java.{util => ju}
1212
import ju.Optional
1313

14+
class TestCallbackNoInc extends TestCallback {
15+
override def enabled(): Boolean = false
16+
}
17+
1418
class TestCallback extends AnalysisCallback2 {
1519
case class TestUsedName(name: String, scopes: ju.EnumSet[UseScope])
1620

0 commit comments

Comments
 (0)