From 24671323c79e58676201f74809829422964293d3 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Mon, 25 Mar 2024 14:12:13 -0700 Subject: [PATCH 1/2] Handle assignment ops --- src/repl/scala/tools/nsc/interpreter/IMain.scala | 3 ++- .../tools/nsc/interpreter/MemberHandlers.scala | 16 +++++++++++++--- test/files/run/repl-assign.check | 3 +++ test/files/run/repl-assign.scala | 1 + 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index afd23b48992..524481c2fe8 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -19,9 +19,9 @@ import java.net.URL import scala.collection.mutable, mutable.ListBuffer import scala.language.implicitConversions import scala.reflect.{ClassTag, classTag} +import scala.reflect.internal.{FatalError, Flags, MissingRequirementError, NoPhase, Precedence} import scala.reflect.internal.util.ScalaClassLoader.URLClassLoader import scala.reflect.internal.util.{AbstractFileClassLoader, BatchSourceFile, ListOfNil, Position, ReplBatchSourceFile, SourceFile} -import scala.reflect.internal.{FatalError, Flags, MissingRequirementError, NoPhase} import scala.reflect.runtime.{universe => ru} import scala.tools.nsc.{Global, Settings} import scala.tools.nsc.interpreter.Results.{Error, Incomplete, Result, Success} @@ -813,6 +813,7 @@ class IMain(val settings: Settings, parentClassLoaderOverride: Option[ClassLoade case init :+ tree => def loop(scrut: Tree): Tree = scrut match { case _: Assign => tree + case Apply(Select(_, op), _) if Precedence(op.decoded).level == 0 => tree case _: RefTree | _: TermTree => storeInVal(tree) case Annotated(_, arg) => loop(arg) case _ => tree diff --git a/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala b/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala index 9bcd6f81af4..76de7b2c26a 100644 --- a/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala +++ b/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala @@ -15,6 +15,7 @@ package scala.tools.nsc.interpreter import scala.language.implicitConversions import scala.collection.mutable +import scala.reflect.internal.Precedence trait MemberHandlers { val intp: IMain @@ -77,7 +78,9 @@ trait MemberHandlers { case member: ModuleDef => new ModuleHandler(member) case member: ClassDef => new ClassHandler(member) case member: TypeDef => new TypeAliasHandler(member) - case member: Assign => new AssignHandler(member) + case member: Assign => AssignHandler(member) + case member @ Apply(Select(_, op), _) + if Precedence(op.decoded).level == 0 => AssignHandler(member) case member: Import => new ImportHandler(member.duplicate) // duplicate because the same tree will be type checked (which loses info) case DocDef(_, documented) => chooseHandler(documented) case member => new GenericHandler(member) @@ -175,9 +178,16 @@ trait MemberHandlers { def notification(req: Request) = s"def ${req.defTypeOf(name)}" } - class AssignHandler(member: Assign) extends MemberHandler(member) { + class AssignHandler private (member: Tree, lhs: Tree) extends MemberHandler(member) { override def resultExtractionCode(req: Request) = - codegenln(s"// mutated ${member.lhs}") + codegenln(s"// mutated $lhs") + } + object AssignHandler { + def apply(member: Assign) = new AssignHandler(member, member.lhs) + def apply(member: Apply) = member match { + case Apply(Select(qual, op), _) if Precedence(op.decoded).level == 0 => new AssignHandler(member, qual) + case _ => new GenericHandler(member) + } } class ModuleHandler(module: ModuleDef) extends MemberDefHandler(module) { diff --git a/test/files/run/repl-assign.check b/test/files/run/repl-assign.check index 300638ba520..4a709b3f897 100644 --- a/test/files/run/repl-assign.check +++ b/test/files/run/repl-assign.check @@ -11,4 +11,7 @@ scala> x = 12 scala> y = 13 // mutated y +scala> x += 30 +// mutated x + scala> :quit diff --git a/test/files/run/repl-assign.scala b/test/files/run/repl-assign.scala index 4b540c9557c..8fd2eac5141 100644 --- a/test/files/run/repl-assign.scala +++ b/test/files/run/repl-assign.scala @@ -6,5 +6,6 @@ var x = 10 var y = 11 x = 12 y = 13 +x += 30 """ } From a17abbaa9b91ca68ff40c7bb36e3c349a040a25d Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Mon, 30 Oct 2023 13:51:38 -0700 Subject: [PATCH 2/2] Tweak repl & test --- .../scala/tools/nsc/interpreter/IMain.scala | 23 +++++++------- test/files/run/repl-assign.check | 17 +++++------ test/files/run/repl-assign.scala | 13 ++------ test/files/run/t8935-object.scala | 30 +------------------ 4 files changed, 22 insertions(+), 61 deletions(-) diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index 524481c2fe8..18678f56932 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -621,16 +621,14 @@ class IMain(val settings: Settings, parentClassLoaderOverride: Option[ClassLoade override lazy val power = new Power(this, new StdReplVals(this))(tagOfStdReplVals, classTag[StdReplVals]) /** Here is where we: - * - * 1) Read some source code, and put it in the "read" object. - * 2) Evaluate the read object, and put the result in the "eval" object. - * 3) Create a String for human consumption, and put it in the "print" object. - * - * Read! Eval! Print! Some of that not yet centralized here. - */ - class ReadEvalPrint(val lineId: Int) { - def this() = this(freshLineId()) - + * + * 1) Read some source code, and put it in the "read" object. + * 2) Evaluate the read object, and put the result in the "eval" object. + * 3) Create a String for human consumption, and put it in the "print" object. + * + * Read! Eval! Print! Some of that not yet centralized here. + */ + class ReadEvalPrint(val lineId: Int = freshLineId()) { val packageName = sessionNames.packageName(lineId) val readName = sessionNames.read val evalName = sessionNames.eval @@ -824,7 +822,7 @@ class IMain(val settings: Settings, parentClassLoaderOverride: Option[ClassLoade } /** handlers for each tree in this request */ - val handlers: List[MemberHandler] = trees map (memberHandlers chooseHandler _) + val handlers: List[MemberHandler] = trees.map(memberHandlers.chooseHandler(_)) val definesValueClass = handlers.exists(_.definesValueClass) val isClassBased = IMain.this.isClassBased && !definesValueClass @@ -968,7 +966,8 @@ class IMain(val settings: Settings, parentClassLoaderOverride: Option[ClassLoade /** Compile the object file. Returns whether the compilation succeeded. - * If all goes well, the "types" map is computed. */ + * If all goes well, the "types" map is computed. + */ def compile: Boolean = { // compile the object containing the user's code diff --git a/test/files/run/repl-assign.check b/test/files/run/repl-assign.check index 4a709b3f897..247fbbd8252 100644 --- a/test/files/run/repl-assign.check +++ b/test/files/run/repl-assign.check @@ -1,17 +1,14 @@ -scala> var x = 10 -var x: Int = 10 +scala> var x = 42 +var x: Int = 42 -scala> var y = 11 -var y: Int = 11 - -scala> x = 12 +scala> x = 17 // mutated x -scala> y = 13 -// mutated y - -scala> x += 30 +scala> x += 10 // mutated x +scala> x +val res0: Int = 27 + scala> :quit diff --git a/test/files/run/repl-assign.scala b/test/files/run/repl-assign.scala index 8fd2eac5141..7c12d3d2b4d 100644 --- a/test/files/run/repl-assign.scala +++ b/test/files/run/repl-assign.scala @@ -1,11 +1,4 @@ -import scala.tools.partest.ReplTest -object Test extends ReplTest { - def code = """ -var x = 10 -var y = 11 -x = 12 -y = 13 -x += 30 - """ -} +import scala.tools.partest.SessionTest + +object Test extends SessionTest diff --git a/test/files/run/t8935-object.scala b/test/files/run/t8935-object.scala index 67704ed028e..7da7b58a505 100644 --- a/test/files/run/t8935-object.scala +++ b/test/files/run/t8935-object.scala @@ -1,31 +1,3 @@ import scala.tools.partest.SessionTest -import scala.tools.nsc.Settings - -object Test extends SessionTest { - /* future - override def transformSettings(s: Settings): Settings = { - //s.YreplWrap.value = "object" - s - } - */ - override def session = -""" -scala> 41+1 -res0: Int = 42 - -scala> $intp.valueOfTerm($intp.mostRecentVar) -res1: Option[Any] = Some(42) - -scala> val i = 17 ; 64 -i: Int = 17 -res2: Int = 64 - -scala> $intp.valueOfTerm($intp.mostRecentVar) -res3: Option[Any] = Some(64) - -scala> $intp.valueOfTerm("i") -res4: Option[Any] = Some(17) - -scala> :quit""" -} +object Test extends SessionTest