Skip to content

Commit 40b9872

Browse files
author
som-snytt
authored
Merge pull request scala#10728 from som-snytt/issue/12894-repl-mutation
REPL handles assignment ops like Assign
2 parents 43f2ae0 + a17abba commit 40b9872

File tree

5 files changed

+37
-61
lines changed

5 files changed

+37
-61
lines changed

src/repl/scala/tools/nsc/interpreter/IMain.scala

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ import java.net.URL
1919
import scala.collection.mutable, mutable.ListBuffer
2020
import scala.language.implicitConversions
2121
import scala.reflect.{ClassTag, classTag}
22+
import scala.reflect.internal.{FatalError, Flags, MissingRequirementError, NoPhase, Precedence}
2223
import scala.reflect.internal.util.ScalaClassLoader.URLClassLoader
2324
import scala.reflect.internal.util.{AbstractFileClassLoader, BatchSourceFile, ListOfNil, Position, ReplBatchSourceFile, SourceFile}
24-
import scala.reflect.internal.{FatalError, Flags, MissingRequirementError, NoPhase}
2525
import scala.reflect.runtime.{universe => ru}
2626
import scala.tools.nsc.{Global, Settings}
2727
import scala.tools.nsc.interpreter.Results.{Error, Incomplete, Result, Success}
@@ -621,16 +621,14 @@ class IMain(val settings: Settings, parentClassLoaderOverride: Option[ClassLoade
621621
override lazy val power = new Power(this, new StdReplVals(this))(tagOfStdReplVals, classTag[StdReplVals])
622622

623623
/** Here is where we:
624-
*
625-
* 1) Read some source code, and put it in the "read" object.
626-
* 2) Evaluate the read object, and put the result in the "eval" object.
627-
* 3) Create a String for human consumption, and put it in the "print" object.
628-
*
629-
* Read! Eval! Print! Some of that not yet centralized here.
630-
*/
631-
class ReadEvalPrint(val lineId: Int) {
632-
def this() = this(freshLineId())
633-
624+
*
625+
* 1) Read some source code, and put it in the "read" object.
626+
* 2) Evaluate the read object, and put the result in the "eval" object.
627+
* 3) Create a String for human consumption, and put it in the "print" object.
628+
*
629+
* Read! Eval! Print! Some of that not yet centralized here.
630+
*/
631+
class ReadEvalPrint(val lineId: Int = freshLineId()) {
634632
val packageName = sessionNames.packageName(lineId)
635633
val readName = sessionNames.read
636634
val evalName = sessionNames.eval
@@ -813,6 +811,7 @@ class IMain(val settings: Settings, parentClassLoaderOverride: Option[ClassLoade
813811
case init :+ tree =>
814812
def loop(scrut: Tree): Tree = scrut match {
815813
case _: Assign => tree
814+
case Apply(Select(_, op), _) if Precedence(op.decoded).level == 0 => tree
816815
case _: RefTree | _: TermTree => storeInVal(tree)
817816
case Annotated(_, arg) => loop(arg)
818817
case _ => tree
@@ -823,7 +822,7 @@ class IMain(val settings: Settings, parentClassLoaderOverride: Option[ClassLoade
823822
}
824823

825824
/** handlers for each tree in this request */
826-
val handlers: List[MemberHandler] = trees map (memberHandlers chooseHandler _)
825+
val handlers: List[MemberHandler] = trees.map(memberHandlers.chooseHandler(_))
827826
val definesValueClass = handlers.exists(_.definesValueClass)
828827

829828
val isClassBased = IMain.this.isClassBased && !definesValueClass
@@ -967,7 +966,8 @@ class IMain(val settings: Settings, parentClassLoaderOverride: Option[ClassLoade
967966

968967

969968
/** Compile the object file. Returns whether the compilation succeeded.
970-
* If all goes well, the "types" map is computed. */
969+
* If all goes well, the "types" map is computed.
970+
*/
971971
def compile: Boolean = {
972972

973973
// compile the object containing the user's code

src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ package scala.tools.nsc.interpreter
1515
import scala.language.implicitConversions
1616

1717
import scala.collection.mutable
18+
import scala.reflect.internal.Precedence
1819

1920
trait MemberHandlers {
2021
val intp: IMain
@@ -77,7 +78,9 @@ trait MemberHandlers {
7778
case member: ModuleDef => new ModuleHandler(member)
7879
case member: ClassDef => new ClassHandler(member)
7980
case member: TypeDef => new TypeAliasHandler(member)
80-
case member: Assign => new AssignHandler(member)
81+
case member: Assign => AssignHandler(member)
82+
case member @ Apply(Select(_, op), _)
83+
if Precedence(op.decoded).level == 0 => AssignHandler(member)
8184
case member: Import => new ImportHandler(member.duplicate) // duplicate because the same tree will be type checked (which loses info)
8285
case DocDef(_, documented) => chooseHandler(documented)
8386
case member => new GenericHandler(member)
@@ -175,9 +178,16 @@ trait MemberHandlers {
175178
def notification(req: Request) = s"def ${req.defTypeOf(name)}"
176179
}
177180

178-
class AssignHandler(member: Assign) extends MemberHandler(member) {
181+
class AssignHandler private (member: Tree, lhs: Tree) extends MemberHandler(member) {
179182
override def resultExtractionCode(req: Request) =
180-
codegenln(s"// mutated ${member.lhs}")
183+
codegenln(s"// mutated $lhs")
184+
}
185+
object AssignHandler {
186+
def apply(member: Assign) = new AssignHandler(member, member.lhs)
187+
def apply(member: Apply) = member match {
188+
case Apply(Select(qual, op), _) if Precedence(op.decoded).level == 0 => new AssignHandler(member, qual)
189+
case _ => new GenericHandler(member)
190+
}
181191
}
182192

183193
class ModuleHandler(module: ModuleDef) extends MemberDefHandler(module) {

test/files/run/repl-assign.check

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11

2-
scala> var x = 10
3-
var x: Int = 10
2+
scala> var x = 42
3+
var x: Int = 42
44

5-
scala> var y = 11
6-
var y: Int = 11
5+
scala> x = 17
6+
// mutated x
77

8-
scala> x = 12
8+
scala> x += 10
99
// mutated x
1010

11-
scala> y = 13
12-
// mutated y
11+
scala> x
12+
val res0: Int = 27
1313

1414
scala> :quit

test/files/run/repl-assign.scala

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
import scala.tools.partest.ReplTest
21

3-
object Test extends ReplTest {
4-
def code = """
5-
var x = 10
6-
var y = 11
7-
x = 12
8-
y = 13
9-
"""
10-
}
2+
import scala.tools.partest.SessionTest
3+
4+
object Test extends SessionTest

test/files/run/t8935-object.scala

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,3 @@
11
import scala.tools.partest.SessionTest
22

3-
import scala.tools.nsc.Settings
4-
5-
object Test extends SessionTest {
6-
/* future
7-
override def transformSettings(s: Settings): Settings = {
8-
//s.YreplWrap.value = "object"
9-
s
10-
}
11-
*/
12-
override def session =
13-
"""
14-
scala> 41+1
15-
res0: Int = 42
16-
17-
scala> $intp.valueOfTerm($intp.mostRecentVar)
18-
res1: Option[Any] = Some(42)
19-
20-
scala> val i = 17 ; 64
21-
i: Int = 17
22-
res2: Int = 64
23-
24-
scala> $intp.valueOfTerm($intp.mostRecentVar)
25-
res3: Option[Any] = Some(64)
26-
27-
scala> $intp.valueOfTerm("i")
28-
res4: Option[Any] = Some(17)
29-
30-
scala> :quit"""
31-
}
3+
object Test extends SessionTest

0 commit comments

Comments
 (0)