Skip to content

Add native Dotty REPL #2991

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 90 commits into from
Aug 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
7687f4b
Add initial scaffolding for REPL project
felixmulder Jun 5, 2017
cb1332c
Add ammonite sources and implement prompt with highlighting
felixmulder Jun 5, 2017
11dceca
Add multiline support
felixmulder Jun 8, 2017
a40175e
Apply workaround for #2711
felixmulder Jun 8, 2017
f9d48ec
Refactor side-effecty logic in AmmoniteReader
felixmulder Jun 8, 2017
a7a7c9a
Replace command by ADT
felixmulder Jun 8, 2017
a7b5460
Fix sbt `run` in `dotty-repl`
felixmulder Jun 9, 2017
c96ce66
Get rid of interactive compiler in REPL
felixmulder Jun 9, 2017
38e2649
Implement compilation without need for reparsing trees
felixmulder Jun 9, 2017
e6f678b
Move typechecking to throwaway class
felixmulder Jun 12, 2017
0a3532d
Turn ReplCompiler into ReplTyper
felixmulder Jun 12, 2017
905ada0
Clean up compilation logic, make union decorator work
felixmulder Jun 13, 2017
358c3a9
Add crash tests
felixmulder Jun 15, 2017
774a21f
Add test for tree injector
felixmulder Jun 15, 2017
8b1352d
Implement fresh injection of trees into `ReplSession` object
felixmulder Jun 15, 2017
1b129cd
Use single compiler instance instead of split pipeline
felixmulder Jun 16, 2017
3520967
Modularize compilation steps
felixmulder Jun 16, 2017
fbf90e5
Get rid of union either, clean up `repl.State`
felixmulder Jun 19, 2017
a43e3f5
Add printing of definition names and kinds
felixmulder Jun 20, 2017
a807b30
Implement showing of basic results
felixmulder Jun 20, 2017
fcbb4f7
Use semantic names encoding in repl
felixmulder Jun 20, 2017
2697436
Don't evaluate lazy vals
felixmulder Jun 20, 2017
1efb41a
Add missing type case to render
felixmulder Jun 20, 2017
e4241d5
Only evaluate side-effecty expression once
felixmulder Jun 20, 2017
260f4f1
Allow args to commands
felixmulder Jun 20, 2017
9b35296
Compile expressions with show
felixmulder Jun 21, 2017
f674efb
Implement `:type <expr>`
felixmulder Jun 21, 2017
d44b246
Clean up `ParseResult.scala`
felixmulder Jun 22, 2017
a71122c
Fix `:type` depending on existing variables
felixmulder Jun 22, 2017
49d62fa
Add ability to customize repl `out`
felixmulder Jun 22, 2017
2f64d98
Add tests, fix `var` rendering
felixmulder Jun 23, 2017
692aa6a
Don't add type to `...Show` methods
felixmulder Jun 23, 2017
a83fe4f
Add support for `import x`
felixmulder Jun 26, 2017
28d3004
Keep history even on unsuccessful readLines
felixmulder Jun 26, 2017
63dbd86
Add support for `:imports`
felixmulder Jun 26, 2017
51a1af4
Migrate compilation to context based imports
felixmulder Jun 27, 2017
b11c634
Add magic imports to `:type` checking as well
felixmulder Jun 27, 2017
88f5c0e
Make sure nested contexts get a fresh scope
felixmulder Jun 27, 2017
128e053
Make the `dotty-repl` the default repl in Build.scala
felixmulder Jun 28, 2017
497adf8
Partially update ammonite to 6883f48
felixmulder Jun 28, 2017
bbc5a14
Split typeOf into typeCheck and typeOf
felixmulder Jun 29, 2017
3ca99b6
Port tab-completion from ammonite, implement dummy completion
felixmulder Jun 29, 2017
4932444
Propagate TermAction instead of String from Terminal.readLine
felixmulder Jun 30, 2017
4b13494
Fix highlighting of capital letter selections e.g: `x.Y`
felixmulder Jun 30, 2017
8d75b73
Filter string representation of typedefs
felixmulder Jun 30, 2017
2d791cc
Fix rebinding of vars
felixmulder Jul 3, 2017
62e1abc
Make repl work with interactive API for tab-completion
felixmulder Aug 2, 2017
ad2b7dc
Make tab-completion use basic filtering
felixmulder Aug 2, 2017
347b351
Add tabcomplete tests
felixmulder Aug 3, 2017
24d5845
Add IDE modes to `myCtx` in Repl.scala
felixmulder Aug 3, 2017
3e33a3b
Make sure test context has a `StoreReporter`
felixmulder Aug 3, 2017
b0b216c
Fix crash in Interactive when boundary is `NoSymbol`
felixmulder Aug 3, 2017
0a8c384
Filter `Artifact` and `Synthetic` from IDE
felixmulder Aug 3, 2017
1e9a835
Make pattern matcher's `isInstanceOf` synthetic
felixmulder Aug 3, 2017
1175916
Clean up and add docstrings
felixmulder Aug 7, 2017
b89b84e
fixup tab-completion tests
felixmulder Aug 8, 2017
54f0b5c
Refactor Repl run interface to yield `State` instead of `Unit`
felixmulder Aug 8, 2017
85ef9f2
Add new `UserFacingPrinter` instead of using `RefinedPrinter` w hacks
felixmulder Aug 8, 2017
ead77da
Move `isInfixType` to member of `Type`
felixmulder Aug 9, 2017
fcf6332
Cover more of the language in the user facing printer
felixmulder Aug 10, 2017
800bf17
Use time travel to properly print definitions in Repl
felixmulder Aug 10, 2017
77e44a9
Make `Interactive.completions` return completion point
felixmulder Aug 10, 2017
ebc7788
Harden tab completion
felixmulder Aug 10, 2017
0d86885
Don't use `Apply` on free expressions for `.show`
felixmulder Aug 10, 2017
d8808a5
Handle assignments correctly in REPL
felixmulder Aug 11, 2017
fc78787
Make UserFacingPrinter extend PlainPrinter for deduplication
felixmulder Aug 11, 2017
596d54a
Add tests from old repl to new
felixmulder Aug 11, 2017
514ad1b
Move `rootContext` method to Run from Compiler
felixmulder Aug 15, 2017
aae9234
Make isValidAt safer to use
felixmulder Aug 15, 2017
adf9697
Rewrite logic in compiler to use newRun and shadowing classloader
felixmulder Aug 15, 2017
db2205b
Add method `isRunnable` to `Phase` instead of adhoc checking
felixmulder Aug 16, 2017
86e9e31
Add configurable `compileUnits` method to `Run`
felixmulder Aug 16, 2017
f0b20f1
Refactor ReplDriver to use a state with a `Run` instead of `Context`
felixmulder Aug 16, 2017
9e44871
Use `StdNames` constants instead of hardcoded literals
felixmulder Aug 17, 2017
2372340
Make the show member a `DefDef`
felixmulder Aug 17, 2017
96daa58
Get rid of hardcoded library in repl tests
felixmulder Aug 17, 2017
6ae8853
Remove more duplication from UserFacingPrinter
felixmulder Aug 17, 2017
c9e6074
Change Driver API to not need definition of `newCompiler`
felixmulder Aug 17, 2017
a6b0aa1
Remove `newCompiler` override from ReplDriver
felixmulder Aug 17, 2017
9a0a742
Make sure compilation yields a state with a new `Run`
felixmulder Aug 17, 2017
1375e79
Fix missing case for widlcard in UserFacingPrinter
felixmulder Aug 17, 2017
0aa7533
Kill old REPL with 🔥
felixmulder Aug 17, 2017
64862a0
Temporarily disable console in sbt bridge
felixmulder Aug 17, 2017
bc48498
Turn `dotty-repl` project into a Scala 2 project
felixmulder Aug 18, 2017
ec6fbbb
Make new REPL work with sbt bridge
felixmulder Aug 22, 2017
5f8672c
Replace `Result` with right biased Either alias
felixmulder Aug 22, 2017
d601fdf
Add instructions on how to add `initialCommands` to REPL
felixmulder Aug 22, 2017
8c78e9a
Add null-check to `<id>Show` method
felixmulder Aug 23, 2017
dd17d1e
Don't aggregate on dotty-repl in sbt script
felixmulder Aug 23, 2017
331892e
Address reviewer feedback
felixmulder Aug 23, 2017
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
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ val `dotty-bench-bootstrapped` = Build.`dotty-bench-bootstrapped`
val `scala-library` = Build.`scala-library`
val `scala-compiler` = Build.`scala-compiler`
val `scala-reflect` = Build.`scala-reflect`
val `dotty-repl` = Build.`dotty-repl`
val scalap = Build.scalap
val dist = Build.dist
val `dist-bootstrapped` = Build.`dist-bootstrapped`
Expand Down
2 changes: 0 additions & 2 deletions compiler/src/dotty/tools/dotc/Bench.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ object Bench extends Driver {

@sharable private var numRuns = 1

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

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

Expand Down
30 changes: 1 addition & 29 deletions compiler/src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -116,41 +116,13 @@ class Compiler {
runId += 1; runId
}

/** Produces the following contexts, from outermost to innermost
*
* bootStrap: A context with next available runId and a scope consisting of
* the RootPackage _root_
* start A context with RootClass as owner and the necessary initializations
* for type checking.
* imports For each element of RootImports, an import context
*/
def rootContext(implicit ctx: Context): Context = {
ctx.initialize()(ctx)
ctx.setPhasePlan(phases)
val rootScope = new MutableScope
val bootstrap = ctx.fresh
.setPeriod(Period(nextRunId, FirstPhaseId))
.setScope(rootScope)
rootScope.enter(ctx.definitions.RootPackage)(bootstrap)
val start = bootstrap.fresh
.setOwner(defn.RootClass)
.setTyper(new Typer)
.addMode(Mode.ImplicitsEnabled)
.setTyperState(new MutableTyperState(ctx.typerState, ctx.typerState.reporter, isCommittable = true))
.setFreshNames(new FreshNameCreator.Default)
ctx.initialize()(start) // re-initialize the base context with start
def addImport(ctx: Context, refFn: () => TermRef) =
ctx.fresh.setImportInfo(ImportInfo.rootImport(refFn)(ctx))
(start.setRunInfo(new RunInfo(start)) /: defn.RootImportFns)(addImport)
}

def reset()(implicit ctx: Context): Unit = {
ctx.base.reset()
ctx.runInfo.clear()
}

def newRun(implicit ctx: Context): Run = {
reset()
new Run(this)(rootContext)
new Run(this, ctx)
}
}
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/Driver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import scala.util.control.NonFatal
* process, but in most cases you only need to call [[process]] on the
* existing object [[Main]].
*/
abstract class Driver extends DotClass {
class Driver extends DotClass {

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

protected def emptyReporter: Reporter = new StoreReporter(null)

Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/FromTasty.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ object FromTasty extends Driver {

override def newRun(implicit ctx: Context): Run = {
reset()
new TASTYRun(this)(rootContext)
new TASTYRun(this, ctx)
}
}

class TASTYRun(comp: Compiler)(implicit ctx: Context) extends Run(comp) {
class TASTYRun(comp: Compiler, ictx: Context) extends Run(comp, ictx) {
override def compile(classNames: List[String]) = {
units = classNames.map(new TASTYCompilationUnit(_))
compileUnits()
Expand Down
4 changes: 1 addition & 3 deletions compiler/src/dotty/tools/dotc/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@ package dotc
import core.Contexts.Context

/** Main class of the `dotc` batch compiler. */
object Main extends Driver {
override def newCompiler(implicit ctx: Context): Compiler = new Compiler
}
object Main extends Driver
2 changes: 0 additions & 2 deletions compiler/src/dotty/tools/dotc/Resident.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ class Resident extends Driver {

object residentCompiler extends Compiler

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

override def sourcesRequired = false

private val quit = ":q"
Expand Down
52 changes: 47 additions & 5 deletions compiler/src/dotty/tools/dotc/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import Contexts._
import Periods._
import Symbols._
import Phases._
import Types._
import Scopes._
import typer.{FrontEnd, Typer, ImportInfo, RefChecks}
import Decorators._
import dotty.tools.dotc.transform.TreeTransforms.TreeTransformer
import io.PlainFile
Expand All @@ -22,12 +25,41 @@ import dotty.tools.io.VirtualFile
import scala.util.control.NonFatal

/** A compiler run. Exports various methods to compile source files */
class Run(comp: Compiler)(implicit ctx: Context) {

assert(ctx.runId <= Periods.MaxPossibleRunId)
class Run(comp: Compiler, ictx: Context) {

var units: List[CompilationUnit] = _

/** Produces the following contexts, from outermost to innermost
*
* bootStrap: A context with next available runId and a scope consisting of
* the RootPackage _root_
* start A context with RootClass as owner and the necessary initializations
* for type checking.
* imports For each element of RootImports, an import context
*/
protected[this] def rootContext(implicit ctx: Context): Context = {
ctx.initialize()(ctx)
ctx.setPhasePlan(comp.phases)
val rootScope = new MutableScope
val bootstrap = ctx.fresh
.setPeriod(Period(comp.nextRunId, FirstPhaseId))
.setScope(rootScope)
rootScope.enter(ctx.definitions.RootPackage)(bootstrap)
val start = bootstrap.fresh
.setOwner(defn.RootClass)
.setTyper(new Typer)
.addMode(Mode.ImplicitsEnabled)
.setTyperState(new MutableTyperState(ctx.typerState, ctx.typerState.reporter, isCommittable = true))
.setFreshNames(new FreshNameCreator.Default)
ctx.initialize()(start) // re-initialize the base context with start
def addImport(ctx: Context, refFn: () => TermRef) =
ctx.fresh.setImportInfo(ImportInfo.rootImport(refFn)(ctx))
(start.setRunInfo(new RunInfo(start)) /: defn.RootImportFns)(addImport)
}

protected[this] implicit val ctx: Context = rootContext(ictx)
assert(ctx.runId <= Periods.MaxPossibleRunId)

def getSource(fileName: String): SourceFile = {
val f = new PlainFile(fileName)
if (f.isDirectory) {
Expand Down Expand Up @@ -63,7 +95,17 @@ class Run(comp: Compiler)(implicit ctx: Context) {
compileUnits()
}

protected def compileUnits() = Stats.monitorHeartBeat {
def compileUnits(us: List[CompilationUnit]): Unit = {
units = us
compileUnits()
}

def compileUnits(us: List[CompilationUnit], ctx: Context): Unit = {
units = us
compileUnits()(ctx)
}

protected def compileUnits()(implicit ctx: Context) = Stats.monitorHeartBeat {
ctx.checkSingleThreaded()

// If testing pickler, make sure to stop after pickling phase:
Expand All @@ -76,7 +118,7 @@ class Run(comp: Compiler)(implicit ctx: Context) {
ctx.usePhases(phases)
var lastPrintedTree: PrintedTree = NoPrintedTree
for (phase <- ctx.allPhases)
if (!ctx.reporter.hasErrors) {
if (phase.isRunnable) {
val start = System.currentTimeMillis
units = phase.runOn(units)
if (ctx.settings.Xprint.value.containsPhase(phase)) {
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ class Definitions {
lazy val Any_getClass = enterMethod(AnyClass, nme.getClass_, MethodType(Nil, ClassClass.typeRef.appliedTo(TypeBounds.empty)), Final)
lazy val Any_isInstanceOf = enterT1ParameterlessMethod(AnyClass, nme.isInstanceOf_, _ => BooleanType, Final)
lazy val Any_asInstanceOf = enterT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, TypeParamRef(_, 0), Final)
lazy val Any_typeTest = enterT1ParameterlessMethod(AnyClass, nme.isInstanceOfPM, _ => BooleanType, Final)
lazy val Any_typeTest = enterT1ParameterlessMethod(AnyClass, nme.isInstanceOfPM, _ => BooleanType, Final | Synthetic)
// generated by pattern matcher, eliminated by erasure

def AnyMethods = List(Any_==, Any_!=, Any_equals, Any_hashCode,
Expand Down Expand Up @@ -863,8 +863,8 @@ class Definitions {
)

val PredefImportFns = List[() => TermRef](
() => ScalaPredefModuleRef,
() => DottyPredefModuleRef
() => ScalaPredefModuleRef,
() => DottyPredefModuleRef
)

lazy val RootImportFns =
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/core/NameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ object NameOps {
def isConstructorName = name == CONSTRUCTOR || name == TRAIT_CONSTRUCTOR
def isStaticConstructorName = name == STATIC_CONSTRUCTOR
def isLocalDummyName = name startsWith str.LOCALDUMMY_PREFIX
def isReplWrapperName = name.toString contains str.INTERPRETER_IMPORT_WRAPPER
def isReplWrapperName = name.toString contains str.REPL_SESSION_LINE
def isReplAssignName = name.toString contains str.REPL_ASSIGN_SUFFIX
def isSetterName = name endsWith str.SETTER_SUFFIX
def isScala2LocalSuffix = testSimple(_.endsWith(" "))
def isSelectorName = testSimple(n => n.startsWith("_") && n.drop(1).forall(_.isDigit))
Expand Down
5 changes: 5 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Phases.scala
Original file line number Diff line number Diff line change
Expand Up @@ -272,11 +272,16 @@ object Phases {
*/
def phaseName: String

def isRunnable(implicit ctx: Context): Boolean =
!ctx.reporter.hasErrors

/** List of names of phases that should precede this phase */
def runsAfter: Set[Class[_ <: Phase]] = Set.empty

/** @pre `isRunnable` returns true */
def run(implicit ctx: Context): Unit

/** @pre `isRunnable` returns true */
def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] =
units.map { unit =>
val unitCtx = ctx.fresh.setPhase(this.start).setCompilationUnit(unit)
Expand Down
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ object StdNames {
final val ANON_CLASS = "$anon"
final val ANON_FUN = "$anonfun"

final val INTERPRETER_IMPORT_WRAPPER = "$iw"
final val INTERPRETER_LINE_PREFIX = "line"
final val INTERPRETER_VAR_PREFIX = "res"
final val INTERPRETER_WRAPPER_SUFFIX = "$object"
final val REPL_SESSION_LINE = "rs$line$"
final val REPL_ASSIGN_SUFFIX = "$assign"
final val REPL_RES_PREFIX = "res"

final val MODULE_INSTANCE_FIELD = "MODULE$"

final val Function = "Function"
Expand Down
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1994,7 +1994,9 @@ object SymDenotations {
}

def isValidAt(phase: Phase)(implicit ctx: Context) =
createdAt.runId == ctx.runId && sameGroup(ctx.phases(createdAt.phaseId), phase)
createdAt.runId == ctx.runId &&
createdAt.phaseId < ctx.phases.length &&
sameGroup(ctx.phases(createdAt.phaseId), phase)
}

private class InvalidCache extends InheritedCache {
Expand Down
8 changes: 8 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,14 @@ object Types {
false
}

def isInfixType(implicit ctx: Context): Boolean = this match {
case TypeApplications.AppliedType(tycon, args) =>
args.length == 2 &&
!Character.isUnicodeIdentifierStart(tycon.typeSymbol.name.toString.head)
// TODO: Once we use the 2.12 stdlib, also check the @showAsInfix annotation
case _ => false
}

/** Does this type refer exactly to class symbol `sym`, instead of to a subclass of `sym`?
* Implemented like `isRef`, but follows more types: all type proxies as well as and- and or-types
*/
Expand Down
52 changes: 34 additions & 18 deletions compiler/src/dotty/tools/dotc/interactive/Interactive.scala
Original file line number Diff line number Diff line change
Expand Up @@ -65,35 +65,51 @@ object Interactive {
private def safely[T](op: => List[T]): List[T] =
try op catch { case ex: TypeError => Nil }

/** Possible completions at position `pos` */
def completions(trees: List[SourceTree], pos: SourcePosition)(implicit ctx: Context): List[Symbol] = {
/** Get possible completions from tree at `pos`
*
* @return offset and list of symbols for possible completions
*/
def completions(trees: List[SourceTree], pos: SourcePosition)(implicit ctx: Context): (Int, List[Symbol]) = {
val path = pathTo(trees, pos)
val boundary = enclosingDefinitionInPath(path).symbol

path.take(1).flatMap {
case Select(qual, _) =>
// FIXME: Get all declarations available in the current scope, not just
// those from the enclosing class
def scopeCompletions: List[Symbol] =
boundary.enclosingClass match {
case csym: ClassSymbol =>
val classRef = csym.classInfo.typeRef
completions(classRef, boundary)
case _ =>
Nil
}

path.headOption.map {
case sel @ Select(qual, name) =>
// When completing "`a.foo`, return the members of `a`
completions(qual.tpe, boundary)
(sel.pos.point, completions(qual.tpe, boundary))
case id @ Ident(name) =>
(id.pos.point, scopeCompletions)
case _ =>
// FIXME: Get all declarations available in the current scope, not just
// those from the enclosing class
boundary.enclosingClass match {
case csym: ClassSymbol =>
val classRef = csym.classInfo.typeRef
completions(classRef, boundary)
case _ =>
Nil
}
(0, scopeCompletions)
}
.getOrElse((0, Nil))
}

/** Possible completions of members of `prefix` which are accessible when called inside `boundary` */
def completions(prefix: Type, boundary: Symbol)(implicit ctx: Context): List[Symbol] =
safely {
val boundaryCtx = ctx.withOwner(boundary)
prefix.memberDenots(completionsFilter, (name, buf) =>
buf ++= prefix.member(name).altsWith(d => !d.isAbsent && d.symbol.isAccessibleFrom(prefix)(boundaryCtx))
).map(_.symbol).toList
if (boundary != NoSymbol) {
val boundaryCtx = ctx.withOwner(boundary)
prefix.memberDenots(completionsFilter, (name, buf) =>
buf ++= prefix.member(name).altsWith{ d =>
!d.isAbsent &&
!d.is(Synthetic) && !d.is(Artifact) &&
d.symbol.isAccessibleFrom(prefix)(boundaryCtx)
}
).map(_.symbol).toList
}
else Nil
}

/** Filter for names that should appear when looking for completions. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ class InteractiveDriver(settings: List[String]) extends Driver {
import tpd._
import InteractiveDriver._

// FIXME: Change the Driver API to not require implementing this method
override protected def newCompiler(implicit ctx: Context): Compiler = ???
override def sourcesRequired = false

private val myInitCtx: Context = {
Expand Down
14 changes: 3 additions & 11 deletions compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -125,23 +125,15 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
("implicit " provided isImplicit) ~ argStr ~ " => " ~ argText(args.last)
}

def isInfixType(tp: Type): Boolean = tp match {
case AppliedType(tycon, args) =>
args.length == 2 &&
!Character.isUnicodeIdentifierStart(tycon.typeSymbol.name.toString.head)
// TODO: Once we use the 2.12 stdlib, also check the @showAsInfix annotation
case _ =>
false
}
def toTextInfixType(op: Type, args: List[Type]): Text = {
/* SLS 3.2.8: all infix types have the same precedence.
* In A op B op' C, op and op' need the same associativity.
* Therefore, if op is left associative, anything on its right
* needs to be parenthesized if it's an infix type, and vice versa. */
val l :: r :: Nil = args
val isRightAssoc = op.typeSymbol.name.endsWith(":")
val leftArg = if (isRightAssoc && isInfixType(l)) "(" ~ toText(l) ~ ")" else toText(l)
val rightArg = if (!isRightAssoc && isInfixType(r)) "(" ~ toText(r) ~ ")" else toText(r)
val leftArg = if (isRightAssoc && l.isInfixType) "(" ~ toText(l) ~ ")" else toText(l)
val rightArg = if (!isRightAssoc && r.isInfixType) "(" ~ toText(r) ~ ")" else toText(r)

leftArg ~ " " ~ toTextLocal(op) ~ " " ~ rightArg
}
Expand All @@ -154,7 +146,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
if (tycon.isRepeatedParam) return toTextLocal(args.head) ~ "*"
if (defn.isFunctionClass(cls)) return toTextFunction(args, cls.name.isImplicitFunction)
if (defn.isTupleClass(cls)) return toTextTuple(args)
if (isInfixType(tp)) return toTextInfixType(tycon, args)
if (tp.isInfixType) return toTextInfixType(tycon, args)
case EtaExpansion(tycon) =>
return toText(tycon)
case tp: TypeRef =>
Expand Down
Loading