forked from scala/scala3
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add capture checking the compiler as a test (scala#16292)
- Copy compiler code base into a separate test - Adapt code base so that it can be capture checked Based on scala#16254 Only the last two commits are new: - [57527c4](scala@57527c4) copies the compiler codebase as a separate test. - [6dfeaa7](scala@6dfeaa7) makes the changes so that it passes capture checking.
- Loading branch information
Showing
449 changed files
with
146,583 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package dotty.tools | ||
package dotc | ||
|
||
import core.Contexts._ | ||
import reporting.Reporter | ||
import io.AbstractFile | ||
|
||
import scala.annotation.internal.sharable | ||
|
||
/** A main class for running compiler benchmarks. Can instantiate a given | ||
* number of compilers and run each (sequentially) a given number of times | ||
* on the same sources. | ||
*/ | ||
object Bench extends Driver: | ||
|
||
@sharable private var numRuns = 1 | ||
|
||
private def ntimes(n: Int)(op: => Reporter): Reporter = | ||
(0 until n).foldLeft(emptyReporter)((_, _) => op) | ||
|
||
@sharable private var times: Array[Int] = _ | ||
|
||
override def doCompile(compiler: Compiler, files: List[AbstractFile])(using Context): Reporter = | ||
times = new Array[Int](numRuns) | ||
var reporter: Reporter = emptyReporter | ||
for i <- 0 until numRuns do | ||
val start = System.nanoTime() | ||
reporter = super.doCompile(compiler, files) | ||
times(i) = ((System.nanoTime - start) / 1000000).toInt | ||
println(s"time elapsed: ${times(i)}ms") | ||
if ctx.settings.Xprompt.value then | ||
print("hit <return> to continue >") | ||
System.in.nn.read() | ||
println() | ||
reporter | ||
|
||
def extractNumArg(args: Array[String], name: String, default: Int = 1): (Int, Array[String]) = { | ||
val pos = args indexOf name | ||
if (pos < 0) (default, args) | ||
else (args(pos + 1).toInt, (args take pos) ++ (args drop (pos + 2))) | ||
} | ||
|
||
def reportTimes() = | ||
val best = times.sorted | ||
val measured = numRuns / 3 | ||
val avgBest = best.take(measured).sum / measured | ||
val avgLast = times.reverse.take(measured).sum / measured | ||
println(s"best out of $numRuns runs: ${best(0)}") | ||
println(s"average out of best $measured: $avgBest") | ||
println(s"average out of last $measured: $avgLast") | ||
|
||
override def process(args: Array[String], rootCtx: Context): Reporter = | ||
val (numCompilers, args1) = extractNumArg(args, "#compilers") | ||
val (numRuns, args2) = extractNumArg(args1, "#runs") | ||
this.numRuns = numRuns | ||
var reporter: Reporter = emptyReporter | ||
for i <- 0 until numCompilers do | ||
reporter = super.process(args2, rootCtx) | ||
reportTimes() | ||
reporter | ||
|
||
end Bench | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
package dotty.tools | ||
package dotc | ||
|
||
import core._ | ||
import Contexts._ | ||
import SymDenotations.ClassDenotation | ||
import Symbols._ | ||
import util.{FreshNameCreator, SourceFile, NoSource} | ||
import util.Spans.Span | ||
import ast.{tpd, untpd} | ||
import tpd.{Tree, TreeTraverser} | ||
import ast.Trees.{Import, Ident} | ||
import typer.Nullables | ||
import transform.SymUtils._ | ||
import core.Decorators._ | ||
import config.{SourceVersion, Feature} | ||
import StdNames.nme | ||
import scala.annotation.internal.sharable | ||
|
||
class CompilationUnit protected (val source: SourceFile) { | ||
|
||
override def toString: String = source.toString | ||
|
||
var untpdTree: untpd.Tree = untpd.EmptyTree | ||
|
||
var tpdTree: tpd.Tree = tpd.EmptyTree | ||
|
||
/** Is this the compilation unit of a Java file */ | ||
def isJava: Boolean = source.file.name.endsWith(".java") | ||
|
||
/** The source version for this unit, as determined by a language import */ | ||
var sourceVersion: Option[SourceVersion] = None | ||
|
||
/** Pickled TASTY binaries, indexed by class. */ | ||
var pickled: Map[ClassSymbol, () => Array[Byte]] = Map() | ||
|
||
/** The fresh name creator for the current unit. | ||
* FIXME(#7661): This is not fine-grained enough to enable reproducible builds, | ||
* see https://github.com/scala/scala/commit/f50ec3c866263448d803139e119b33afb04ec2bc | ||
*/ | ||
val freshNames: FreshNameCreator = new FreshNameCreator.Default | ||
|
||
/** Will be set to `true` if there are inline call that must be inlined after typer. | ||
* The information is used in phase `Inlining` in order to avoid traversing trees that need no transformations. | ||
*/ | ||
var needsInlining: Boolean = false | ||
|
||
/** Set to `true` if inliner added anonymous mirrors that need to be completed */ | ||
var needsMirrorSupport: Boolean = false | ||
|
||
/** Will be set to `true` if contains `Quote`. | ||
* The information is used in phase `Staging`/`Splicing`/`PickleQuotes` in order to avoid traversing trees that need no transformations. | ||
*/ | ||
var needsStaging: Boolean = false | ||
|
||
/** Will be set to true if the unit contains a captureChecking language import */ | ||
var needsCaptureChecking: Boolean = false | ||
|
||
/** Will be set to true if the unit contains a pureFunctions language import */ | ||
var knowsPureFuns: Boolean = false | ||
|
||
var suspended: Boolean = false | ||
var suspendedAtInliningPhase: Boolean = false | ||
|
||
/** Can this compilation unit be suspended */ | ||
def isSuspendable: Boolean = true | ||
|
||
/** Suspends the compilation unit by thowing a SuspendException | ||
* and recording the suspended compilation unit | ||
*/ | ||
def suspend()(using Context): Nothing = | ||
assert(isSuspendable) | ||
if !suspended then | ||
if (ctx.settings.XprintSuspension.value) | ||
report.echo(i"suspended: $this") | ||
suspended = true | ||
ctx.run.nn.suspendedUnits += this | ||
if ctx.phase == Phases.inliningPhase then | ||
suspendedAtInliningPhase = true | ||
throw CompilationUnit.SuspendException() | ||
|
||
private var myAssignmentSpans: Map[Int, List[Span]] | Null = null | ||
|
||
/** A map from (name-) offsets of all local variables in this compilation unit | ||
* that can be tracked for being not null to the list of spans of assignments | ||
* to these variables. | ||
*/ | ||
def assignmentSpans(using Context): Map[Int, List[Span]] = | ||
if myAssignmentSpans == null then myAssignmentSpans = Nullables.assignmentSpans | ||
myAssignmentSpans.nn | ||
} | ||
|
||
@sharable object NoCompilationUnit extends CompilationUnit(NoSource) { | ||
|
||
override def isJava: Boolean = false | ||
|
||
override def suspend()(using Context): Nothing = | ||
throw CompilationUnit.SuspendException() | ||
|
||
override def assignmentSpans(using Context): Map[Int, List[Span]] = Map.empty | ||
} | ||
|
||
object CompilationUnit { | ||
|
||
class SuspendException extends Exception | ||
|
||
/** Make a compilation unit for top class `clsd` with the contents of the `unpickled` tree */ | ||
def apply(clsd: ClassDenotation, unpickled: Tree, forceTrees: Boolean)(using Context): CompilationUnit = | ||
val file = clsd.symbol.associatedFile.nn | ||
apply(SourceFile(file, Array.empty[Char]), unpickled, forceTrees) | ||
|
||
/** Make a compilation unit, given picked bytes and unpickled tree */ | ||
def apply(source: SourceFile, unpickled: Tree, forceTrees: Boolean)(using Context): CompilationUnit = { | ||
assert(!unpickled.isEmpty, unpickled) | ||
val unit1 = new CompilationUnit(source) | ||
unit1.tpdTree = unpickled | ||
if (forceTrees) { | ||
val force = new Force | ||
force.traverse(unit1.tpdTree) | ||
unit1.needsStaging = force.containsQuote | ||
unit1.needsInlining = force.containsInline | ||
} | ||
unit1 | ||
} | ||
|
||
/** Create a compilation unit corresponding to `source`. | ||
* If `mustExist` is true, this will fail if `source` does not exist. | ||
*/ | ||
def apply(source: SourceFile, mustExist: Boolean = true)(using Context): CompilationUnit = { | ||
val src = | ||
if (!mustExist) | ||
source | ||
else if (source.file.isDirectory) { | ||
report.error(s"expected file, received directory '${source.file.path}'") | ||
NoSource | ||
} | ||
else if (!source.file.exists) { | ||
report.error(s"source file not found: ${source.file.path}") | ||
NoSource | ||
} | ||
else source | ||
new CompilationUnit(src) | ||
} | ||
|
||
/** Force the tree to be loaded */ | ||
private class Force extends TreeTraverser { | ||
var containsQuote = false | ||
var containsInline = false | ||
var containsCaptureChecking = false | ||
def traverse(tree: Tree)(using Context): Unit = { | ||
if (tree.symbol.isQuote) | ||
containsQuote = true | ||
if tree.symbol.is(Flags.Inline) then | ||
containsInline = true | ||
tree match | ||
case Import(qual, selectors) => | ||
tpd.languageImport(qual) match | ||
case Some(prefix) => | ||
for case untpd.ImportSelector(untpd.Ident(imported), untpd.EmptyTree, _) <- selectors do | ||
Feature.handleGlobalLanguageImport(prefix, imported) | ||
case _ => | ||
case _ => | ||
traverseChildren(tree) | ||
} | ||
} | ||
} |
Oops, something went wrong.