Skip to content

Commit 7a893f5

Browse files
committed
Merge pull request #1082 from dotty-staging/add-repl
Dotty REPL initial version
2 parents 24a5fbe + f96f4a2 commit 7a893f5

23 files changed

+1367
-23
lines changed

src/dotty/tools/backend/jvm/DottyBackendInterface.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import NameOps._
3232
import StdNames.nme
3333
import NameOps._
3434

35-
class DottyBackendInterface()(implicit ctx: Context) extends BackendInterface{
35+
class DottyBackendInterface(outputDirectory: AbstractFile)(implicit ctx: Context) extends BackendInterface{
3636
type Symbol = Symbols.Symbol
3737
type Type = Types.Type
3838
type Tree = tpd.Tree
@@ -734,7 +734,7 @@ class DottyBackendInterface()(implicit ctx: Context) extends BackendInterface{
734734
def setter(clz: Symbol): Symbol = decorateSymbol(sym).setter
735735

736736
def moduleSuffix: String = "" // todo: validate that names already have $ suffix
737-
def outputDirectory: AbstractFile = new PlainDirectory(new Directory(new JFile(ctx.settings.d.value)))
737+
def outputDirectory: AbstractFile = DottyBackendInterface.this.outputDirectory
738738
def pos: Position = sym.pos
739739

740740
def throwsAnnotations: List[Symbol] = Nil

src/dotty/tools/backend/jvm/GenBCode.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import scala.tools.asm.tree._
2929
import dotty.tools.dotc.util.{Positions, DotClass}
3030
import tpd._
3131
import StdNames._
32+
import scala.reflect.io.{Directory, PlainDirectory, AbstractFile}
3233

3334
import scala.tools.nsc.backend.jvm.opt.LocalOpt
3435

@@ -37,9 +38,11 @@ class GenBCode extends Phase {
3738
private val entryPoints = new mutable.HashSet[Symbol]()
3839
def registerEntryPoint(sym: Symbol) = entryPoints += sym
3940

41+
def outputDir(implicit ctx: Context): AbstractFile =
42+
new PlainDirectory(new Directory(new JFile(ctx.settings.d.value)))
4043

4144
def run(implicit ctx: Context): Unit = {
42-
new GenBCodePipeline(entryPoints.toList, new DottyBackendInterface()(ctx))(ctx).run(ctx.compilationUnit.tpdTree)
45+
new GenBCodePipeline(entryPoints.toList, new DottyBackendInterface(outputDir)(ctx))(ctx).run(ctx.compilationUnit.tpdTree)
4346
entryPoints.clear()
4447
}
4548
}

src/dotty/tools/dotc/Bench.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ object Bench extends Driver {
1212

1313
@sharable private var numRuns = 1
1414

15-
def newCompiler(): Compiler = new Compiler
15+
def newCompiler(implicit ctx: Context): Compiler = new Compiler
1616

1717
private def ntimes(n: Int)(op: => Reporter): Reporter =
1818
(emptyReporter /: (0 until n)) ((_, _) => op)

src/dotty/tools/dotc/Driver.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ abstract class Driver extends DotClass {
1010

1111
val prompt = "\ndotc> "
1212

13-
protected def newCompiler(): Compiler
13+
protected def newCompiler(implicit ctx: Context): Compiler
1414

1515
protected def emptyReporter: Reporter = new StoreReporter(null)
1616

@@ -90,7 +90,7 @@ abstract class Driver extends DotClass {
9090
*/
9191
def process(args: Array[String], rootCtx: Context): Reporter = {
9292
val (fileNames, ctx) = setup(args, rootCtx)
93-
doCompile(newCompiler(), fileNames)(ctx)
93+
doCompile(newCompiler(ctx), fileNames)(ctx)
9494
}
9595

9696
def main(args: Array[String]): Unit = {

src/dotty/tools/dotc/FromTasty.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import ast.tpd._
3030
* scala dotty.tools.dotc.FromTasty -Xprint:front extMethods.T
3131
*/
3232
object FromTasty extends Driver {
33-
override def newCompiler(): Compiler = new TASTYCompiler
33+
override def newCompiler(implicit ctx: Context): Compiler = new TASTYCompiler
3434

3535
class TASTYCompiler extends Compiler {
3636

src/dotty/tools/dotc/Main.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ package dotty.tools
22
package dotc
33

44
import core.Contexts.Context
5-
import reporting.Reporter
65

76
/* To do:
87
*/
98
object Main extends Driver {
10-
override def newCompiler(): Compiler = new Compiler
9+
override def newCompiler(implicit ctx: Context): Compiler = new Compiler
1110
}

src/dotty/tools/dotc/Resident.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class Resident extends Driver {
2525

2626
object residentCompiler extends Compiler
2727

28-
override def newCompiler(): Compiler = ???
28+
override def newCompiler(implicit ctx: Context): Compiler = ???
2929

3030
override def sourcesRequired = false
3131

src/dotty/tools/dotc/Run.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ class Run(comp: Compiler)(implicit ctx: Context) {
8282
compileSources(List(new SourceFile(virtualFile)))
8383
}
8484

85+
/** The context created for this run */
86+
def runContext = ctx
87+
8588
/** Print summary; return # of errors encountered */
8689
def printSummary(): Reporter = {
8790
ctx.runInfo.printMaxConstraint()

src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class ScalaSettings extends Settings.SettingGroup {
8989
val showPhases = BooleanSetting("-Xshow-phases", "Print a synopsis of compiler phases.")
9090
val sourceReader = StringSetting("-Xsource-reader", "classname", "Specify a custom method for reading source files.", "")
9191
val XnoValueClasses = BooleanSetting("-Xno-value-classes", "Do not use value classes. Helps debugging.")
92-
92+
val XreplLineWidth = IntSetting("-Xrepl-line-width", "Maximial number of columns per line for REPL output", 390)
9393
val XoldPatmat = BooleanSetting("-Xoldpatmat", "Use the pre-2.10 pattern matcher. Otherwise, the 'virtualizing' pattern matcher is used in 2.10.")
9494
val XnoPatmatAnalysis = BooleanSetting("-Xno-patmat-analysis", "Don't perform exhaustivity/unreachability analysis. Also, ignore @switch annotation.")
9595
val XfullLubs = BooleanSetting("-Xfull-lubs", "Retains pre 2.10 behavior of less aggressive truncation of least upper bounds.")

src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,10 @@ object Denotations {
590590
} while (d ne denot)
591591
this
592592
case _ =>
593-
if (coveredInterval.containsPhaseId(ctx.phaseId)) staleSymbolError
593+
if (coveredInterval.containsPhaseId(ctx.phaseId)) {
594+
if (ctx.debug) ctx.traceInvalid(this)
595+
staleSymbolError
596+
}
594597
else NoDenotation
595598
}
596599

src/dotty/tools/dotc/core/Phases.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,13 @@ object Phases {
347347
override def toString = phaseName
348348
}
349349

350+
/** Replace all instances of `oldPhaseClass` in `current` phases
351+
* by the result of `newPhases` applied to the old phase.
352+
*/
353+
def replace(oldPhaseClass: Class[_ <: Phase], newPhases: Phase => List[Phase], current: List[List[Phase]]): List[List[Phase]] =
354+
current.map(_.flatMap(phase =>
355+
if (oldPhaseClass.isInstance(phase)) newPhases(phase) else phase :: Nil))
356+
350357
/** Dotty deviation: getClass yields Class[_], instead of [Class <: <type of receiver>].
351358
* We can get back the old behavior using this decorator. We should also use the same
352359
* trick for standard getClass.

src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,54 @@ trait SymDenotations { this: Context =>
4545
if (denot.is(ValidForever) || denot.isRefinementClass) true
4646
else {
4747
val initial = denot.initial
48-
if (initial ne denot)
49-
ctx.withPhase(initial.validFor.firstPhaseId).stillValid(initial.asSymDenotation)
50-
else try {
51-
val owner = denot.owner.denot
52-
stillValid(owner) && (
53-
!owner.isClass
54-
|| owner.isRefinementClass
55-
|| (owner.unforcedDecls.lookupAll(denot.name) contains denot.symbol)
56-
|| denot.isSelfSym)
57-
} catch {
58-
case ex: StaleSymbol => false
48+
val firstPhaseId = initial.validFor.firstPhaseId.max(ctx.typerPhase.id)
49+
if ((initial ne denot) || ctx.phaseId != firstPhaseId)
50+
ctx.withPhase(firstPhaseId).stillValidInOwner(initial.asSymDenotation)
51+
else
52+
stillValidInOwner(denot)
53+
}
54+
55+
private[SymDenotations] def stillValidInOwner(denot: SymDenotation): Boolean = try {
56+
val owner = denot.owner.denot
57+
stillValid(owner) && (
58+
!owner.isClass
59+
|| owner.isRefinementClass
60+
|| (owner.unforcedDecls.lookupAll(denot.name) contains denot.symbol)
61+
|| denot.isSelfSym)
62+
} catch {
63+
case ex: StaleSymbol => false
64+
}
65+
66+
/** Explain why symbol is invalid; used for debugging only */
67+
def traceInvalid(denot: Denotation): Boolean = {
68+
def show(d: Denotation) = s"$d#${d.symbol.id}"
69+
def explain(msg: String) = {
70+
println(s"${show(denot)} is invalid at ${this.period} because $msg")
71+
false
72+
}
73+
denot match {
74+
case denot: SymDenotation =>
75+
def explainSym(msg: String) = explain(s"$msg\n defined = ${denot.definedPeriodsString}")
76+
if (denot.is(ValidForever) || denot.isRefinementClass) true
77+
else {
78+
implicit val ctx: Context = this
79+
val initial = denot.initial
80+
if ((initial ne denot) || ctx.phaseId != initial.validFor.firstPhaseId) {
81+
ctx.withPhase(initial.validFor.firstPhaseId).traceInvalid(initial.asSymDenotation)
82+
} else try {
83+
val owner = denot.owner.denot
84+
if (!traceInvalid(owner)) explainSym("owner is invalid")
85+
else if (!owner.isClass || owner.isRefinementClass || denot.isSelfSym) true
86+
else if (owner.unforcedDecls.lookupAll(denot.name) contains denot.symbol) true
87+
else explainSym(s"decls of ${show(owner)} are ${owner.unforcedDecls.lookupAll(denot.name).toList}, do not contain ${denot.symbol}")
88+
} catch {
89+
case ex: StaleSymbol => explainSym(s"$ex was thrown")
90+
}
5991
}
92+
case _ =>
93+
explain("denotation is not a SymDenotation")
6094
}
95+
}
6196
}
6297

6398
object SymDenotations {
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package dotty.tools
2+
package dotc
3+
package repl
4+
5+
import io.AbstractFile
6+
7+
/**
8+
* A class loader that loads files from a {@link scala.tools.nsc.io.AbstractFile}.
9+
*
10+
* @author Lex Spoon
11+
*/
12+
class AbstractFileClassLoader(root: AbstractFile, parent: ClassLoader)
13+
extends ClassLoader(parent)
14+
{
15+
override def findClass(name: String): Class[_] = {
16+
var file: AbstractFile = root
17+
val pathParts = name.split("[./]").toList
18+
for (dirPart <- pathParts.init) {
19+
file = file.lookupName(dirPart, true)
20+
if (file == null) {
21+
throw new ClassNotFoundException(name)
22+
}
23+
}
24+
file = file.lookupName(pathParts.last+".class", false)
25+
if (file == null) {
26+
throw new ClassNotFoundException(name)
27+
}
28+
val bytes = file.toByteArray
29+
defineClass(name, bytes, 0, bytes.length)
30+
}
31+
}

0 commit comments

Comments
 (0)