Skip to content

Commit 0eabef2

Browse files
authored
Allow running tests within a debugger (#25655)
Fix #25633 Also improves the simple ignored-by-default Playground to easily run one test case at a time ## How much have you relied on LLM-based tools in this contribution? not ## How was the solution tested? duh
1 parent 5ad2ba8 commit 0eabef2

File tree

9 files changed

+92
-75
lines changed

9 files changed

+92
-75
lines changed

compiler/test/dotty/tools/TestSources.scala

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,21 @@ import dotty.Properties
1010

1111
object TestSources {
1212

13+
private val isWorkingDirectoryInsideCompiler = Paths.get(".").toAbsolutePath.normalize.endsWith("compiler")
14+
15+
def rootPath(): Path =
16+
if isWorkingDirectoryInsideCompiler
17+
then Paths.get("..")
18+
else Paths.get(".")
19+
20+
def getPath(relative: String): Path =
21+
if isWorkingDirectoryInsideCompiler
22+
then Paths.get("..", relative)
23+
// important to not do `get(".", relative)` (or equivalently `rootPath().resolve(relative)`),
24+
// the rest of the testing framework depends on exact paths,
25+
// so "error in ./x.scala" and "error in x.scala" aren't considered equivalent.
26+
else Paths.get(relative)
27+
1328
// pos tests lists
1429

1530
def posFromTastyExcludelistFile: String = "compiler/test/dotc/pos-from-tasty.excludelist"
@@ -85,7 +100,7 @@ object TestSources {
85100
// load lists
86101

87102
private def loadList(path: String): List[String] = {
88-
val list = Files.readAllLines(Paths.get(path))
103+
val list = Files.readAllLines(getPath(path))
89104
.iterator()
90105
.asScala
91106
.map(_.trim) // allow indentation

compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ class BootstrappedOnlyCompilationTests {
186186
// 1. hack with absolute path for -Xplugin
187187
// 2. copy `pluginFile` to destination
188188
def compileFilesInDir(dir: String, run: Boolean = false): CompilationTest = {
189-
val outDir = defaultOutputDir + "testPlugins/"
189+
val outDir = new java.io.File(defaultOutputDir, "testPlugins")
190190
val sourceDir = new java.io.File(dir)
191191

192192
val dirs = sourceDir.listFiles.toList.filter(_.isDirectory)

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,35 +4,26 @@ package dotc
44

55
import scala.language.unsafeNulls
66

7-
import org.junit.{ Test, BeforeClass, AfterClass, Ignore }
8-
import org.junit.Assert._
9-
import org.junit.Assume._
10-
import org.junit.experimental.categories.Category
11-
12-
import java.io.File
13-
import java.nio.file._
14-
import java.util.stream.{ Stream => JStream }
15-
import scala.jdk.CollectionConverters._
16-
import scala.util.matching.Regex
17-
import scala.concurrent.duration._
18-
import TestSources.sources
19-
import TestSources.scoverageIgnoreExcludelisted
20-
import reporting.TestReporter
21-
import vulpix._
22-
import dotty.tools.dotc.config.ScalaSettings
23-
import dotty.tools.dotc.coverage.Serializer
7+
import org.junit.{ Test, AfterClass }
8+
import org.junit.Assume.*
9+
10+
import java.nio.file.*
11+
import scala.concurrent.duration.*
12+
13+
import dotty.tools.dotc.reporting.TestReporter
14+
import dotty.tools.vulpix.*
2415

2516
class CompilationTests {
26-
import ParallelTesting._
27-
import TestConfiguration._
28-
import CompilationTests._
17+
import ParallelTesting.*
18+
import TestConfiguration.*
19+
import CompilationTests.*
2920
import CompilationTest.aggregateTests
3021

3122
// Positive tests ------------------------------------------------------------
3223

3324
@Test def pos: Unit = {
3425
implicit val testGroup: TestGroup = TestGroup("compilePos")
35-
var tests = List(
26+
val tests = List(
3627
compileFilesInDir("tests/pos", defaultOptions.and("-Wsafe-init", "-Wunused:all", "-Wshadow:private-shadow", "-Wshadow:type-parameter-shadow"), FileFilter.include(TestSources.posLintingAllowlist)),
3728
compileFilesInDir("tests/pos", defaultOptions.and("-Wsafe-init"), FileFilter.exclude(TestSources.posLintingAllowlist)),
3829
compileFilesInDir("tests/pos-deep-subtype", allowDeepSubtypes),
@@ -279,7 +270,7 @@ class CompilationTests {
279270
locally {
280271
val group = TestGroup("checkInitGlobal/tastySource")
281272
val tastSourceOptions = defaultOptions.and("-Ysafe-init-global")
282-
val outDirLib = defaultOutputDir + group + "/A/tastySource/A"
273+
val outDirLib = Paths.get(defaultOutputDir.getAbsolutePath, group.name,"A", "tastySource", "A").toString
283274

284275
// Set -sourceroot such that the source code cannot be found by the compiler
285276
val libOptions = tastSourceOptions.and("-sourceroot", "tests/init-global/special")
@@ -311,8 +302,8 @@ class CompilationTests {
311302
locally {
312303
val i12128Group = TestGroup("checkInit/i12128")
313304
val i12128Options = options.without("-Werror")
314-
val outDir1 = defaultOutputDir + i12128Group + "/Reflect_1/i12128/Reflect_1"
315-
val outDir2 = defaultOutputDir + i12128Group + "/Macro_2/i12128/Macro_2"
305+
val outDir1 = Paths.get(defaultOutputDir.getAbsolutePath, i12128Group.name, "Reflect_1", "i12128", "Reflect_1").toString
306+
val outDir2 = Paths.get(defaultOutputDir.getAbsolutePath, i12128Group.name, "Macro_2", "i12128", "Macro_2").toString
316307

317308
val tests = List(
318309
withCoverage(compileFile("tests/init/special/i12128/Reflect_1.scala", i12128Options)(using i12128Group).keepOutput),
@@ -331,9 +322,9 @@ class CompilationTests {
331322
val tastyErrorGroup = TestGroup("checkInit/tasty-error/val-or-defdef")
332323
val tastyErrorOptions = options.without("-Werror")
333324

334-
val classA0 = defaultOutputDir + tastyErrorGroup + "/A/v0/A"
335-
val classA1 = defaultOutputDir + tastyErrorGroup + "/A/v1/A"
336-
val classB1 = defaultOutputDir + tastyErrorGroup + "/B/v1/B"
325+
val classA0 = Paths.get(defaultOutputDir.getAbsolutePath, tastyErrorGroup.name, "A", "v0", "A").toString
326+
val classA1 = Paths.get(defaultOutputDir.getAbsolutePath, tastyErrorGroup.name, "A", "v1", "A").toString
327+
val classB1 = Paths.get(defaultOutputDir.getAbsolutePath, tastyErrorGroup.name, "B", "v1", "B").toString
337328

338329
val tests = List(
339330
withCoverage(compileFile("tests/init/tasty-error/val-or-defdef/v1/A.scala", tastyErrorOptions)(using tastyErrorGroup).keepOutput),
@@ -355,10 +346,10 @@ class CompilationTests {
355346
val tastyErrorGroup = TestGroup("checkInit/tasty-error/typedef")
356347
val tastyErrorOptions = options.without("-Werror").without("-Ycheck:all")
357348

358-
val classC = defaultOutputDir + tastyErrorGroup + "/C/typedef/C"
359-
val classA0 = defaultOutputDir + tastyErrorGroup + "/A/v0/A"
360-
val classA1 = defaultOutputDir + tastyErrorGroup + "/A/v1/A"
361-
val classB1 = defaultOutputDir + tastyErrorGroup + "/B/v1/B"
349+
val classC = Paths.get(defaultOutputDir.getAbsolutePath, tastyErrorGroup.name, "C", "typedef", "C").toString
350+
val classA0 = Paths.get(defaultOutputDir.getAbsolutePath, tastyErrorGroup.name, "A", "v0", "A").toString
351+
val classA1 = Paths.get(defaultOutputDir.getAbsolutePath, tastyErrorGroup.name, "A", "v1", "A").toString
352+
val classB1 = Paths.get(defaultOutputDir.getAbsolutePath, tastyErrorGroup.name, "B", "v1", "B").toString
362353

363354
val tests = List(
364355
withCoverage(compileFile("tests/init/tasty-error/typedef/C.scala", tastyErrorOptions)(using tastyErrorGroup).keepOutput),
Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
11
package dotty.tools.dotc
22

3-
import dotty.tools.vulpix._
3+
import dotty.tools.vulpix.*
44
import org.junit.Test
55
import org.junit.Ignore
66

7+
// For ease of debugging individual tests
78
@Ignore class Playground:
8-
import TestConfiguration._
9-
import CompilationTests._
9+
import TestConfiguration.*
10+
import CompilationTests.*
11+
import CompilationTest.aggregateTests
1012

1113
@Test def example: Unit =
12-
implicit val testGroup: TestGroup = TestGroup("playground")
13-
compileFile("tests/playground/example.scala", defaultOptions).checkCompile()
14+
implicit val testGroup: TestGroup = TestGroup("single-test")
15+
// can add, e.g., .and("-some-option")
16+
val options = defaultOptions
17+
// can also use `compileDir` (single test as a dir), `compileFilesInDir` (all tests within a dir)
18+
val test = compileFile("tests/pos/tuple-filter.scala", options)
19+
// or `RunTestWithCoverage` for "run" tests with output, or `WarnTestWithCoverage` for "warn" tests with warnings
20+
type TestKind = PosTestWithCoverage
21+
val compilationTest = withCoverage(aggregateTests(test))
22+
runWithCoverageOrFallback[TestKind](compilationTest, testGroup.name)
23+

compiler/test/dotty/tools/dotc/TastyBootstrapTests.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,16 @@ class TastyBootstrapTests {
3737
val dotty2Group = TestGroup("tastyBootstrap/dotty2")
3838

3939
// Make sure that the directory is clean
40-
dotty.tools.io.Directory(defaultOutputDir + "tastyBootstrap").deleteRecursively()
40+
dotty.tools.io.Directory(new java.io.File(defaultOutputDir, "tastyBootstrap").getAbsolutePath).deleteRecursively()
4141

4242
val opt = TestFlags(
4343
List(
4444
// compile with bootstrapped library on cp:
45-
defaultOutputDir + libGroup + "/lib/",
45+
Paths.get(defaultOutputDir.getAbsolutePath, libGroup.name, "lib").toString,
4646
// and bootstrapped tasty-core:
47-
defaultOutputDir + tastyCoreGroup + "/tastyCore/",
47+
Paths.get(defaultOutputDir.getAbsolutePath, tastyCoreGroup.name, "tastyCore").toString,
4848
// as well as bootstrapped compiler:
49-
defaultOutputDir + dotty1Group + "/dotty1/",
49+
Paths.get(defaultOutputDir.getAbsolutePath, dotty1Group.name, "dotty1").toString,
5050
// and the other compiler dependencies:
5151
Properties.compilerInterface, Properties.scalaLibrary, Properties.scalaAsm,
5252
Properties.dottyInterfaces, Properties.jlineTerminal, Properties.jlineReader,

compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,13 @@ import org.junit.experimental.categories.Category
88
import dotty.{BootstrappedOnlyTests, Properties}
99
import dotty.tools.vulpix.*
1010
import dotty.tools.vulpix.TestConfiguration.*
11-
import dotty.tools.dotc.Main
1211
import dotty.tools.dotc.reporting.TestReporter
1312

1413
import java.nio.file.{FileSystems, Files, Path, Paths, StandardCopyOption}
1514
import scala.jdk.CollectionConverters.*
1615
import scala.util.Properties.userDir
1716
import scala.language.unsafeNulls
1817
import scala.collection.mutable.Buffer
19-
import dotty.tools.dotc.util.DiffUtil
2018

2119
import java.nio.charset.StandardCharsets
2220
import java.util.stream.Collectors

compiler/test/dotty/tools/dotc/printing/PrintingTest.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ import java.io.File
2626
class PrintingTest {
2727

2828
def options(phase: String, flags: List[String]) =
29-
val outDir = ParallelTesting.defaultOutputDir + "printing" + File.pathSeparator
30-
File(outDir).mkdirs()
31-
List(s"-Vprint:$phase", "-color:never", "-nowarn", "-d", outDir, "-classpath", TestConfiguration.basicClasspath) ::: flags
29+
val outDir = new File(ParallelTesting.defaultOutputDir, "printing")
30+
outDir.mkdirs()
31+
List(s"-Vprint:$phase", "-color:never", "-nowarn", "-d", outDir.getAbsolutePath, "-classpath", TestConfiguration.basicClasspath) ::: flags
3232

3333
private def compileFile(path: JPath, phase: String): Boolean = {
3434
val baseFilePath = path.toString.stripSuffix(".scala").stripSuffix(".java")

compiler/test/dotty/tools/vulpix/ParallelTesting.scala

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
162162

163163
final override def toString: String = sourceFiles match {
164164
case Array(f) => f.getPath
165-
case _ => outDir.getPath.stripPrefix(defaultOutputDir).stripPrefix(name).stripPrefix("/")
165+
case _ => outDir.getPath.stripPrefix(defaultOutputDirName).stripPrefix(name).stripPrefix("/")
166166
}
167167
}
168168

@@ -507,11 +507,16 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
507507
def scalacOptions = toolArgs.getOrElse(ToolName.Scalac, Nil)
508508
def javacOptions = toolArgs.getOrElse(ToolName.Javac, Nil)
509509

510-
val flags = flags0
510+
var flags = flags0
511511
.and(scalacOptions*)
512512
.and("-d", targetDir.getPath)
513513
.withClasspath(targetDir.getPath)
514514

515+
// We must set -sourceroot for SemanticDB extraction to work properly inside an IDE,
516+
// but we have many existing coverage tests that assume it is not set, so as a workaround:
517+
if !flags.all.contains("-coverage-out") then
518+
flags = flags.and("-sourceroot", TestSources.rootPath().toAbsolutePath.toString)
519+
515520
def compileWithJavac(fs: Array[String]) = if (fs.nonEmpty) {
516521
val fullArgs = Array(
517522
"-encoding", StandardCharsets.UTF_8.name,
@@ -1409,24 +1414,23 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
14091414
end CompilationTest
14101415

14111416
/** Create out directory for directory `d` */
1412-
def createOutputDirsForDir(d: JFile, sourceDir: JFile, outDir: String): JFile = {
1413-
val targetDir = new JFile(outDir + s"${sourceDir.getName}/${d.getName}")
1417+
def createOutputDirsForDir(d: JFile, sourceDir: JFile, outDir: JFile): JFile = {
1418+
val targetDir = new JFile(outDir, s"${sourceDir.getName}/${d.getName}")
14141419
targetDir.mkdirs()
14151420
targetDir
14161421
}
14171422

14181423
/** Create out directory for `file` */
1419-
private def createOutputDirsForFile(file: JFile, sourceDir: JFile, outDir: String): JFile = {
1424+
private def createOutputDirsForFile(file: JFile, sourceDir: JFile, outDir: JFile): JFile = {
14201425
val uniqueSubdir = file.getName.substring(0, file.getName.lastIndexOf('.'))
1421-
val targetDir = new JFile(outDir + s"${sourceDir.getName}${JFile.separatorChar}$uniqueSubdir")
1426+
val targetDir = new JFile(outDir, s"${sourceDir.getName}${JFile.separatorChar}$uniqueSubdir")
14221427
targetDir.mkdirs()
14231428
targetDir
14241429
}
14251430

14261431
/** Make sure that directory string is as expected */
1427-
private def checkRequirements(f: String, sourceDir: JFile, outDir: String): Unit = {
1432+
private def checkRequirements(f: String, sourceDir: JFile, outDir: JFile): Unit = {
14281433
require(sourceDir.isDirectory && sourceDir.exists, "passed non-directory to `compileFilesInDir`: " + sourceDir)
1429-
require(outDir.last == JFile.separatorChar, "please specify an `outDir` with a trailing file separator")
14301434
}
14311435

14321436
/** Separates directories from files and returns them as `(dirs, files)` */
@@ -1440,11 +1444,10 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
14401444

14411445
/** Compiles a single file from the string path `f` using the supplied flags */
14421446
def compileFile(f: String, flags: TestFlags)(implicit testGroup: TestGroup): CompilationTest = {
1443-
val sourceFile = new JFile(f)
1447+
val sourceFile = TestSources.getPath(f).toFile
14441448
val parent = sourceFile.getParentFile
14451449
val outDir =
1446-
defaultOutputDir + testGroup + JFile.separator +
1447-
sourceFile.getName.substring(0, sourceFile.getName.lastIndexOf('.')) + JFile.separator
1450+
new JFile(new JFile(defaultOutputDir, testGroup.name), sourceFile.getName.substring(0, sourceFile.getName.lastIndexOf('.')))
14481451

14491452
require(
14501453
sourceFile.exists && !sourceFile.isDirectory &&
@@ -1469,8 +1472,8 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
14691472
* can be used for randomization.
14701473
*/
14711474
def compileDir(f: String, flags: TestFlags, randomOrder: Option[Int] = None, recursive: Boolean = true)(using testGroup: TestGroup): CompilationTest = {
1472-
val outDir = defaultOutputDir + testGroup + JFile.separator
1473-
val sourceDir = new JFile(f)
1475+
val outDir = new JFile(defaultOutputDir, testGroup.name)
1476+
val sourceDir = TestSources.getPath(f).toFile
14741477
checkRequirements(f, sourceDir, outDir)
14751478

14761479
def flatten(f: JFile): Array[JFile] =
@@ -1488,7 +1491,7 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
14881491
}
14891492

14901493
// Directories in which to compile all containing files with `flags`:
1491-
val targetDir = new JFile(outDir + JFile.separator + sourceDir.getName + JFile.separator)
1494+
val targetDir = new JFile(outDir, sourceDir.getName)
14921495
targetDir.mkdirs()
14931496

14941497
val target = JointCompilationSource(s"compiling '$f' in test '$testGroup'", randomized, flags, targetDir)
@@ -1500,10 +1503,8 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
15001503
* dissociated
15011504
*/
15021505
def compileList(testName: String, files: List[String], flags: TestFlags)(implicit testGroup: TestGroup): CompilationTest = {
1503-
val outDir = defaultOutputDir + testGroup + JFile.separator + testName + JFile.separator
1504-
15051506
// Directories in which to compile all containing files with `flags`:
1506-
val targetDir = new JFile(outDir)
1507+
val targetDir = new JFile(new JFile(defaultOutputDir, testGroup.name), testName)
15071508
targetDir.mkdirs()
15081509
assert(targetDir.exists, s"couldn't create target directory: $targetDir")
15091510

@@ -1531,8 +1532,8 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
15311532
* the same name as the directory (with the file extension `.check`)
15321533
*/
15331534
def compileFilesInDir(f: String, flags: TestFlags, fileFilter: FileFilter = FileFilter.NoFilter)(implicit testGroup: TestGroup): CompilationTest = {
1534-
val outDir = defaultOutputDir + testGroup + JFile.separator
1535-
val sourceDir = new JFile(f)
1535+
val outDir = new JFile(defaultOutputDir, testGroup.name)
1536+
val sourceDir = TestSources.getPath(f).toFile
15361537
checkRequirements(f, sourceDir, outDir)
15371538

15381539
val (dirs, files) = compilationTargets(sourceDir, fileFilter)
@@ -1571,9 +1572,8 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
15711572
* Tests in the first part of the tuple must be executed before the second.
15721573
* Both testsRequires explicit delete().
15731574
*/
1574-
def compileTastyInDir(f: String, flags0: TestFlags, fromTastyFilter: FileFilter)(
1575-
implicit testGroup: TestGroup): TastyCompilationTest = {
1576-
val outDir = defaultOutputDir + testGroup + JFile.separator
1575+
def compileTastyInDir(f: String, flags0: TestFlags, fromTastyFilter: FileFilter)(implicit testGroup: TestGroup): TastyCompilationTest = {
1576+
val outDir = new JFile(defaultOutputDir, testGroup.name)
15771577
val flags = flags0 `and` "-Yretain-trees"
15781578
val sourceDir = new JFile(f)
15791579
checkRequirements(f, sourceDir, outDir)
@@ -1636,7 +1636,7 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
16361636
val semanticDbFlag = "-Xsemanticdb"
16371637
assert(!flags.options.contains(bestEffortFlag), "Best effort compilation flag should not be added manually")
16381638

1639-
val outDir = defaultOutputDir + testGroup + JFile.separator
1639+
val outDir = new JFile(defaultOutputDir, testGroup.name)
16401640
val sourceDir = new JFile(f)
16411641
checkRequirements(f, sourceDir, outDir)
16421642

@@ -1739,7 +1739,7 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
17391739
val step1SourceFiles = step1SourceDir.listFiles
17401740
val step2SourceFiles = step2SourceDir.listFiles
17411741

1742-
val outDir = defaultOutputDir + testGroup + JFile.separator + dir.getName().toString + JFile.separator
1742+
val outDir = new JFile(new JFile(defaultOutputDir, testGroup.name), dir.getName)
17431743

17441744
val step1OutDir = createOutputDirsForDir(step1SourceDir, step1SourceDir, outDir)
17451745
val step2OutDir = createOutputDirsForDir(step2SourceDir, step2SourceDir, outDir)
@@ -1825,7 +1825,7 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
18251825
* tests.
18261826
*/
18271827
def compileShallowFilesInDir(f: String, flags: TestFlags)(implicit testGroup: TestGroup): CompilationTest = {
1828-
val outDir = defaultOutputDir + testGroup + JFile.separator
1828+
val outDir = new JFile(defaultOutputDir, testGroup.name)
18291829
val sourceDir = new JFile(f)
18301830
checkRequirements(f, sourceDir, outDir)
18311831

@@ -1851,7 +1851,8 @@ trait ParallelTesting extends RunnerOrchestration with CoverageSupport:
18511851

18521852
object ParallelTesting:
18531853

1854-
def defaultOutputDir: String = "out"+JFile.separator
1854+
def defaultOutputDirName: String = "out" + JFile.separator
1855+
def defaultOutputDir: JFile = TestSources.getPath(defaultOutputDirName).toFile
18551856

18561857
def isSourceFile(f: JFile): Boolean = {
18571858
val name = f.getName

tests/init-global/special/tastySource/B.check

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
|Reading mutable state of other static objects is forbidden as it breaks initialization-time irrelevance. Calling trace:
66
|├── object B: [ B.scala:1 ]
77
|│ ^
8-
|├── (no source) [ tastySource/A.scala:2 ]
9-
|├── (no source) [ tastySource/A.scala:4 ]
8+
|├── def foo(fn: => Int) = bar(fn) [ A.scala:2 ]
9+
|│ ^^^^^^^
10+
|├── def bar(fn: => Int) = fn [ A.scala:4 ]
11+
|│ ^^
1012
|├── var y = A.foo(bar) * 2 [ B.scala:2 ]
1113
|│ ^^^
1214
|└── def bar = C.n * 3 // warn [ B.scala:4 ]

0 commit comments

Comments
 (0)