Skip to content

Dotty REPL initial version #1082

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Feb 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/dotty/tools/backend/jvm/DottyBackendInterface.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import NameOps._
import StdNames.nme
import NameOps._

class DottyBackendInterface()(implicit ctx: Context) extends BackendInterface{
class DottyBackendInterface(outputDirectory: AbstractFile)(implicit ctx: Context) extends BackendInterface{
type Symbol = Symbols.Symbol
type Type = Types.Type
type Tree = tpd.Tree
Expand Down Expand Up @@ -734,7 +734,7 @@ class DottyBackendInterface()(implicit ctx: Context) extends BackendInterface{
def setter(clz: Symbol): Symbol = decorateSymbol(sym).setter

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

def throwsAnnotations: List[Symbol] = Nil
Expand Down
5 changes: 4 additions & 1 deletion src/dotty/tools/backend/jvm/GenBCode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import scala.tools.asm.tree._
import dotty.tools.dotc.util.{Positions, DotClass}
import tpd._
import StdNames._
import scala.reflect.io.{Directory, PlainDirectory, AbstractFile}

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

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

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

def run(implicit ctx: Context): Unit = {
new GenBCodePipeline(entryPoints.toList, new DottyBackendInterface()(ctx))(ctx).run(ctx.compilationUnit.tpdTree)
new GenBCodePipeline(entryPoints.toList, new DottyBackendInterface(outputDir)(ctx))(ctx).run(ctx.compilationUnit.tpdTree)
entryPoints.clear()
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/Bench.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ object Bench extends Driver {

@sharable private var numRuns = 1

def newCompiler(): Compiler = new Compiler
def newCompiler(implicit ctx: Context): Compiler = new Compiler

private def ntimes(n: Int)(op: => Reporter): Reporter =
(emptyReporter /: (0 until n)) ((_, _) => op)
Expand Down
4 changes: 2 additions & 2 deletions src/dotty/tools/dotc/Driver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ abstract class Driver extends DotClass {

val prompt = "\ndotc> "

protected def newCompiler(): Compiler
protected def newCompiler(implicit ctx: Context): Compiler

protected def emptyReporter: Reporter = new StoreReporter(null)

Expand Down Expand Up @@ -90,7 +90,7 @@ abstract class Driver extends DotClass {
*/
def process(args: Array[String], rootCtx: Context): Reporter = {
val (fileNames, ctx) = setup(args, rootCtx)
doCompile(newCompiler(), fileNames)(ctx)
doCompile(newCompiler(ctx), fileNames)(ctx)
}

def main(args: Array[String]): Unit = {
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/FromTasty.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import ast.tpd._
* scala dotty.tools.dotc.FromTasty -Xprint:front extMethods.T
*/
object FromTasty extends Driver {
override def newCompiler(): Compiler = new TASTYCompiler
override def newCompiler(implicit ctx: Context): Compiler = new TASTYCompiler

class TASTYCompiler extends Compiler {

Expand Down
3 changes: 1 addition & 2 deletions src/dotty/tools/dotc/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ package dotty.tools
package dotc

import core.Contexts.Context
import reporting.Reporter

/* To do:
*/
object Main extends Driver {
override def newCompiler(): Compiler = new Compiler
override def newCompiler(implicit ctx: Context): Compiler = new Compiler
}
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/Resident.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class Resident extends Driver {

object residentCompiler extends Compiler

override def newCompiler(): Compiler = ???
override def newCompiler(implicit ctx: Context): Compiler = ???

override def sourcesRequired = false

Expand Down
3 changes: 3 additions & 0 deletions src/dotty/tools/dotc/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ class Run(comp: Compiler)(implicit ctx: Context) {
compileSources(List(new SourceFile(virtualFile)))
}

/** The context created for this run */
def runContext = ctx

/** Print summary; return # of errors encountered */
def printSummary(): Reporter = {
ctx.runInfo.printMaxConstraint()
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class ScalaSettings extends Settings.SettingGroup {
val showPhases = BooleanSetting("-Xshow-phases", "Print a synopsis of compiler phases.")
val sourceReader = StringSetting("-Xsource-reader", "classname", "Specify a custom method for reading source files.", "")
val XnoValueClasses = BooleanSetting("-Xno-value-classes", "Do not use value classes. Helps debugging.")

val XreplLineWidth = IntSetting("-Xrepl-line-width", "Maximial number of columns per line for REPL output", 390)
val XoldPatmat = BooleanSetting("-Xoldpatmat", "Use the pre-2.10 pattern matcher. Otherwise, the 'virtualizing' pattern matcher is used in 2.10.")
val XnoPatmatAnalysis = BooleanSetting("-Xno-patmat-analysis", "Don't perform exhaustivity/unreachability analysis. Also, ignore @switch annotation.")
val XfullLubs = BooleanSetting("-Xfull-lubs", "Retains pre 2.10 behavior of less aggressive truncation of least upper bounds.")
Expand Down
5 changes: 4 additions & 1 deletion src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,10 @@ object Denotations {
} while (d ne denot)
this
case _ =>
if (coveredInterval.containsPhaseId(ctx.phaseId)) staleSymbolError
if (coveredInterval.containsPhaseId(ctx.phaseId)) {
if (ctx.debug) ctx.traceInvalid(this)
staleSymbolError
}
else NoDenotation
}

Expand Down
7 changes: 7 additions & 0 deletions src/dotty/tools/dotc/core/Phases.scala
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,13 @@ object Phases {
override def toString = phaseName
}

/** Replace all instances of `oldPhaseClass` in `current` phases
* by the result of `newPhases` applied to the old phase.
*/
def replace(oldPhaseClass: Class[_ <: Phase], newPhases: Phase => List[Phase], current: List[List[Phase]]): List[List[Phase]] =
current.map(_.flatMap(phase =>
if (oldPhaseClass.isInstance(phase)) newPhases(phase) else phase :: Nil))

/** Dotty deviation: getClass yields Class[_], instead of [Class <: <type of receiver>].
* We can get back the old behavior using this decorator. We should also use the same
* trick for standard getClass.
Expand Down
57 changes: 46 additions & 11 deletions src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,54 @@ trait SymDenotations { this: Context =>
if (denot.is(ValidForever) || denot.isRefinementClass) true
else {
val initial = denot.initial
if (initial ne denot)
ctx.withPhase(initial.validFor.firstPhaseId).stillValid(initial.asSymDenotation)
else try {
val owner = denot.owner.denot
stillValid(owner) && (
!owner.isClass
|| owner.isRefinementClass
|| (owner.unforcedDecls.lookupAll(denot.name) contains denot.symbol)
|| denot.isSelfSym)
} catch {
case ex: StaleSymbol => false
val firstPhaseId = initial.validFor.firstPhaseId.max(ctx.typerPhase.id)
if ((initial ne denot) || ctx.phaseId != firstPhaseId)
ctx.withPhase(firstPhaseId).stillValidInOwner(initial.asSymDenotation)
else
stillValidInOwner(denot)
}

private[SymDenotations] def stillValidInOwner(denot: SymDenotation): Boolean = try {
val owner = denot.owner.denot
stillValid(owner) && (
!owner.isClass
|| owner.isRefinementClass
|| (owner.unforcedDecls.lookupAll(denot.name) contains denot.symbol)
|| denot.isSelfSym)
} catch {
case ex: StaleSymbol => false
}

/** Explain why symbol is invalid; used for debugging only */
def traceInvalid(denot: Denotation): Boolean = {
def show(d: Denotation) = s"$d#${d.symbol.id}"
def explain(msg: String) = {
println(s"${show(denot)} is invalid at ${this.period} because $msg")
false
}
denot match {
case denot: SymDenotation =>
def explainSym(msg: String) = explain(s"$msg\n defined = ${denot.definedPeriodsString}")
if (denot.is(ValidForever) || denot.isRefinementClass) true
else {
implicit val ctx: Context = this
val initial = denot.initial
if ((initial ne denot) || ctx.phaseId != initial.validFor.firstPhaseId) {
ctx.withPhase(initial.validFor.firstPhaseId).traceInvalid(initial.asSymDenotation)
} else try {
val owner = denot.owner.denot
if (!traceInvalid(owner)) explainSym("owner is invalid")
else if (!owner.isClass || owner.isRefinementClass || denot.isSelfSym) true
else if (owner.unforcedDecls.lookupAll(denot.name) contains denot.symbol) true
else explainSym(s"decls of ${show(owner)} are ${owner.unforcedDecls.lookupAll(denot.name).toList}, do not contain ${denot.symbol}")
} catch {
case ex: StaleSymbol => explainSym(s"$ex was thrown")
}
}
case _ =>
explain("denotation is not a SymDenotation")
}
}
}

object SymDenotations {
Expand Down
31 changes: 31 additions & 0 deletions src/dotty/tools/dotc/repl/AbstractFileClassLoader.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package dotty.tools
package dotc
package repl

import io.AbstractFile

/**
* A class loader that loads files from a {@link scala.tools.nsc.io.AbstractFile}.
*
* @author Lex Spoon
*/
class AbstractFileClassLoader(root: AbstractFile, parent: ClassLoader)
extends ClassLoader(parent)
{
override def findClass(name: String): Class[_] = {
var file: AbstractFile = root
val pathParts = name.split("[./]").toList
for (dirPart <- pathParts.init) {
file = file.lookupName(dirPart, true)
if (file == null) {
throw new ClassNotFoundException(name)
}
}
file = file.lookupName(pathParts.last+".class", false)
if (file == null) {
throw new ClassNotFoundException(name)
}
val bytes = file.toByteArray
defineClass(name, bytes, 0, bytes.length)
}
}
Loading