Skip to content

Commit fbf90e5

Browse files
committed
Get rid of union either, clean up repl.State
1 parent 3520967 commit fbf90e5

File tree

4 files changed

+74
-58
lines changed

4 files changed

+74
-58
lines changed

repl/src/dotty/tools/repl/Repl.scala

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@ import dotc.{ Compiler, Driver }
1313
import AmmoniteReader._
1414
import results._
1515

16-
case class State(objectIndex: Int, valIndex: Int, history: History, ictx: Context)
17-
object State {
18-
def initial(ctx: Context): State = new State(0, 0, Nil, ctx)
19-
}
16+
case class State(objectIndex: Int, valIndex: Int, history: History)
2017

2118
class Repl(settings: Array[String]) extends Driver {
2219

@@ -38,15 +35,14 @@ class Repl(settings: Array[String]) extends Driver {
3835
private def readLine(history: History) =
3936
AmmoniteReader(history)(myCtx).prompt()
4037

41-
@tailrec
42-
final def run(state: State = State.initial(myCtx)): Unit =
38+
@tailrec final def run(state: State = State(0, 0, Nil)): Unit =
4339
readLine(state.history) match {
4440
case (parsed: Parsed, history) =>
4541
val newState = compile(parsed, state)
4642
run(newState.copy(history = history))
4743

4844
case (SyntaxErrors(errs, ctx), history) =>
49-
displayErrors(errs)(ctx)
45+
displayErrors(errs)(myCtx)
5046
run(state)
5147

5248
case (Newline, history) =>
@@ -57,17 +53,16 @@ class Repl(settings: Array[String]) extends Driver {
5753
}
5854

5955
def compile(parsed: Parsed, state: State): State = {
60-
implicit val ctx = state.ictx
56+
implicit val ctx = myCtx
6157
compiler
6258
.compile(parsed, state)
6359
.fold(
6460
errors => {
65-
displayErrors(errors.msgs)
61+
displayErrors(errors)
6662
state
6763
},
68-
state => {
69-
myCtx = state.ictx
70-
state
64+
(unit, newState) => {
65+
newState
7166
}
7267
)
7368
}

repl/src/dotty/tools/repl/ReplCompiler.scala

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,11 @@ class ReplCompiler(ictx: Context) extends Compiler {
6767
)
6868
}
6969

70-
def freeToAssigned(trees: Seq[untpd.Tree], state: State): (State, Seq[untpd.Tree]) = {
70+
sealed case class Definitions(trees: Seq[untpd.Tree], state: State)
71+
72+
def definitions(trees: Seq[untpd.Tree], state: State): Result[Definitions] = {
7173
import untpd._
72-
implicit val ctx = state.ictx
74+
implicit val ctx = ictx
7375

7476
def freeExpression(t: Tree) =
7577
t.isTerm && !t.isInstanceOf[Assign]
@@ -80,7 +82,10 @@ class ReplCompiler(ictx: Context) extends Compiler {
8082
.withPos(exp.pos)
8183
}
8284

83-
(state.copy(valIndex = state.valIndex + resX.length), resX ++ other)
85+
Definitions(
86+
resX ++ other,
87+
state.copy(valIndex = state.valIndex + resX.length)
88+
).result
8489
}
8590

8691
def wrapped(trees: Seq[untpd.Tree], nextId: Int)(implicit ctx: Context): untpd.PackageDef = {
@@ -102,30 +107,29 @@ class ReplCompiler(ictx: Context) extends Compiler {
102107
def createUnit(trees: Seq[untpd.Tree], objectIndex: Int, sourceCode: String)(implicit ctx: Context): Result[CompilationUnit] = {
103108
val unit = new CompilationUnit(new SourceFile(s"ReplsSession$$$objectIndex", sourceCode))
104109
unit.untpdTree = wrapped(trees, objectIndex)
105-
unit
110+
unit.result
106111
}
107112

108113
def runCompilation(unit: CompilationUnit, state: State): Result[State] = {
109-
implicit val ctx = state.ictx
114+
implicit val ctx = ictx
110115
val reporter = new StoreReporter(null) with UniqueMessagePositions with HideNonSensicalMessages
111116
val run = newRun(ctx.fresh.setReporter(reporter))
112117
run.compileUnits(unit :: Nil)
113118

114119
val errs = reporter.removeBufferedMessages
115120
if (errs.isEmpty) state.copy(
116121
objectIndex = state.objectIndex + 1,
117-
valIndex = state.valIndex,
118-
ictx = run.runContext
119-
)
120-
else Errors(errs)
122+
valIndex = state.valIndex
123+
).result
124+
else errs.errors
121125
}
122126

123-
def compile(parsed: Parsed, state: State): Result[State] = {
124-
implicit val ctx = state.ictx
127+
def compile(parsed: Parsed, state: State): Result[(CompilationUnit, State)] = {
128+
implicit val ctx = ictx
125129
for {
126-
stateAndTrees <- freeToAssigned(parsed.trees, state)
127-
unit <- createUnit(stateAndTrees._2, state.objectIndex, parsed.sourceCode)
128-
state <- runCompilation(unit, stateAndTrees._1)
129-
} yield state
130+
defs <- definitions(parsed.trees, state)
131+
unit <- createUnit(defs.trees, state.objectIndex, parsed.sourceCode)
132+
state <- runCompilation(unit, defs.state)
133+
} yield (unit, state)
130134
}
131135
}

repl/src/dotty/tools/repl/results.scala

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,34 @@ package repl
44
import dotc.reporting.diagnostic.MessageContainer
55

66
object results {
7-
type Result[A] = Errors | A
7+
type Errors = Seq[MessageContainer]
88

9-
case class Errors(msgs: Seq[MessageContainer])
9+
/** A result of a computation is either a list of errors or the result `A` */
10+
class Result[A] private[results] (result: Errors | A) {
11+
def flatMap[B](f: A => Result[B]): Result[B] =
12+
result match {
13+
case errs: Errors => new Result(errs)
14+
case a: A @unchecked => f(a)
15+
}
1016

11-
implicit class RichResult[A](val res: Result[A]) /*extends AnyVal */{
12-
def map[B](f: A => B): Result[B] = res match {
13-
case errs: Errors => errs
14-
case a: A => f(a)
15-
}
17+
def map[B](f: A => B): Result[B] =
18+
result match {
19+
case errs: Errors => new Result(errs)
20+
case a: A @unchecked => new Result(f(a))
21+
}
1622

17-
def flatMap[B](f: A => Result[B]): Result[B] = map(f)
23+
def fold[B](onErrors: Errors => B, onResult: A => B): B =
24+
result match {
25+
case errs: Errors => onErrors(errs)
26+
case a: A @unchecked => onResult(a)
27+
}
28+
}
1829

19-
def fold[B](left: Errors => B, right: A => B): B = res match {
20-
case errors: Errors => left(errors)
21-
case a: A => right(a)
22-
}
30+
implicit class ResultConversionA[A](val a: A) extends AnyVal {
31+
def result: Result[A] = new Result(a)
2332
}
2433

25-
def id[A](a: A): a.type = a
34+
implicit class ResultConversionErr(val xs: Errors) extends AnyVal {
35+
def errors[A]: Result[A] = new Result[A](xs)
36+
}
2637
}

repl/test/dotty/tools/repl/CompilerTests.scala

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,48 +4,54 @@ package repl
44
import org.junit.Assert._
55
import org.junit.Test
66

7+
import dotc.reporting.diagnostic.MessageContainer
78
import dotc.ast.untpd
89

910
import results._
1011

1112
class ReplCompilerTests extends ReplTest {
13+
14+
def onErrors(xs: Seq[MessageContainer]): Unit =
15+
fail(s"Expected no errors, got: \n${ xs.map(_.message).mkString("\n") }")
16+
1217
@Test def compileSingle = {
1318
val parsed @ Parsed(_,_) = ParseResult("def foo: 1 = 1")(myCtx)
14-
val res = compiler.compile(parsed, State.initial(myCtx))
15-
assert(res.isInstanceOf[State],
16-
s"Assumed value of `typeCheck` would be TypedTrees - but got: $res")
19+
compiler
20+
.compile(parsed, State(0, 0, Nil))
21+
.fold(onErrors(_), _ => ())
1722
}
1823

1924
@Test def compileTwo = {
25+
implicit val ctx = myCtx
2026
val parsed @ Parsed(_,_) = ParseResult("def foo: 1 = 1")(myCtx)
2127

2228
compiler
23-
.compile(parsed, State.initial(myCtx))
24-
.flatMap { state =>
25-
val parsed @ Parsed(_,_) = ParseResult("def foo(i: Int): i.type = i")(state.ictx)
26-
compiler.compile(parsed, state.copy(ictx = myCtx))
29+
.compile(parsed, State(0, 0, Nil))
30+
.flatMap { (unit, state) =>
31+
val parsed @ Parsed(_,_) = ParseResult("def foo(i: Int): i.type = i")
32+
compiler.compile(parsed, state)
2733
}
2834
.fold(
29-
error =>
30-
fail(s"Expected no errors, got: \n${ error.msgs.map(_.message).mkString("\n") }"),
31-
state =>
35+
onErrors(_),
36+
(unit, state) => {
3237
assert(state.objectIndex == 2,
3338
s"Wrong object offset: expected 2 got ${state.objectIndex}")
39+
}
3440
)
3541
}
3642

3743
@Test def inspectSingle = {
38-
val parsed @ Parsed(_,_) = ParseResult("def foo: 1 = 1")(myCtx)
44+
implicit val ctx = myCtx
45+
val parsed @ Parsed(_,_) = ParseResult("def foo: 1 = 1")
3946
val res = for {
40-
stateAndTrees <- compiler.freeToAssigned(parsed.trees, State.initial(myCtx))
41-
(State(objectIndex, _, _, ictx), trees) = stateAndTrees
42-
unit <- compiler.createUnit(trees, objectIndex, parsed.sourceCode)(myCtx)
43-
} yield (unit.untpdTree, ictx)
47+
defs <- compiler.definitions(parsed.trees, State(0, 0, Nil))
48+
unit <- compiler.createUnit(defs.trees, defs.state.objectIndex, parsed.sourceCode)
49+
} yield unit.untpdTree
4450

4551
res.fold(
46-
error => fail(s"received errors: ${error.msgs}"),
47-
(tree, ictx) => {
48-
implicit val ctx = ictx
52+
onErrors(_),
53+
tree => {
54+
implicit val ctx = myCtx
4955

5056
tree match {
5157
case untpd.PackageDef(_, List(mod: untpd.ModuleDef)) =>

0 commit comments

Comments
 (0)