From 86ae2f95ce33ef22f9c9ad40d6a966fbef7d352f Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Thu, 7 Apr 2016 12:32:40 -0700 Subject: SI-9740 Repl import fix -Yrepl-class-based Under `-Yrepl-class-based`, templating must follow the same scoping as under traditional object-based. The new test shows a typical case where two values of the same simple name must be imported in different scopes. --- src/repl/scala/tools/nsc/interpreter/Imports.scala | 35 +++++++------ src/repl/scala/tools/nsc/interpreter/package.scala | 9 ++-- test/files/jvm/interpreter.check | 2 +- test/files/run/repl-classbased.check | 23 +++++++++ test/files/run/repl-classbased.scala | 22 ++++++++ test/files/run/repl-javap-app.check | 60 ---------------------- test/files/run/repl-javap-app.scala | 15 +++--- test/files/run/t7319.check | 6 +-- 8 files changed, 80 insertions(+), 92 deletions(-) create mode 100644 test/files/run/repl-classbased.check create mode 100644 test/files/run/repl-classbased.scala diff --git a/src/repl/scala/tools/nsc/interpreter/Imports.scala b/src/repl/scala/tools/nsc/interpreter/Imports.scala index f04e2e808c..71a5e9f00a 100644 --- a/src/repl/scala/tools/nsc/interpreter/Imports.scala +++ b/src/repl/scala/tools/nsc/interpreter/Imports.scala @@ -127,7 +127,11 @@ trait Imports { case rh :: rest if !keepHandler(rh.handler) => select(rest, wanted) case rh :: rest => import rh.handler._ - val newWanted = wanted ++ referencedNames -- definedNames -- importedNames + val augment = rh match { + case ReqAndHandler(_, _: ImportHandler) => referencedNames // for "import a.b", add "a" to names to be resolved + case _ => Nil + } + val newWanted = wanted ++ augment -- definedNames -- importedNames rh :: select(rest, newWanted) } } @@ -161,6 +165,8 @@ trait Imports { val tempValLines = mutable.Set[Int]() for (ReqAndHandler(req, handler) <- reqsToUse) { val objName = req.lineRep.readPathInstance + if (isReplTrace) + code.append(ss"// $objName definedNames ${handler.definedNames}, curImps $currentImps\n") handler match { case h: ImportHandler if checkHeader(h) => header.clear() @@ -175,21 +181,20 @@ trait Imports { currentImps ++= x.importedNames case x if isClassBased => - for (imv <- x.definedNames) { - if (!currentImps.contains(imv)) { - x match { - case _: ClassHandler => - code.append("import " + objName + req.accessPath + ".`" + imv + "`\n") - case _ => - val valName = req.lineRep.packageName + req.lineRep.readName - if (!tempValLines.contains(req.lineRep.lineId)) { - code.append(s"val $valName: ${objName}.type = $objName\n") - tempValLines += req.lineRep.lineId - } - code.append(s"import $valName${req.accessPath}.`$imv`;\n") - } - currentImps += imv + for (sym <- x.definedSymbols) { + maybeWrap(sym.name) + x match { + case _: ClassHandler => + code.append(s"import ${objName}${req.accessPath}.`${sym.name}`\n") + case _ => + val valName = s"${req.lineRep.packageName}${req.lineRep.readName}" + if (!tempValLines.contains(req.lineRep.lineId)) { + code.append(s"val $valName: ${objName}.type = $objName\n") + tempValLines += req.lineRep.lineId + } + code.append(s"import ${valName}${req.accessPath}.`${sym.name}`\n") } + currentImps += sym.name } // For other requests, import each defined name. // import them explicitly instead of with _, so that diff --git a/src/repl/scala/tools/nsc/interpreter/package.scala b/src/repl/scala/tools/nsc/interpreter/package.scala index 56f1e65376..7934d819b4 100644 --- a/src/repl/scala/tools/nsc/interpreter/package.scala +++ b/src/repl/scala/tools/nsc/interpreter/package.scala @@ -198,13 +198,14 @@ package object interpreter extends ReplConfig with ReplStrings { } } - /* debug assist + /* An s-interpolator that uses `stringOf(arg)` instead of `String.valueOf(arg)`. */ private[nsc] implicit class `smart stringifier`(val sc: StringContext) extends AnyVal { import StringContext._, runtime.ScalaRunTime.stringOf def ss(args: Any*): String = sc.standardInterpolator(treatEscapes, args map stringOf) - } debug assist */ + } + /* Try (body) lastly (more) */ private[nsc] implicit class `try lastly`[A](val t: Try[A]) extends AnyVal { - private def effect[X](last: =>Unit)(a: X): Try[A] = { last; t } - def lastly(last: =>Unit): Try[A] = t transform (effect(last) _, effect(last) _) + private def effect[X](last: => Unit)(a: X): Try[A] = { last; t } + def lastly(last: => Unit): Try[A] = t transform (effect(last) _, effect(last) _) } } diff --git a/test/files/jvm/interpreter.check b/test/files/jvm/interpreter.check index ce3c8062d7..9a2162a906 100644 --- a/test/files/jvm/interpreter.check +++ b/test/files/jvm/interpreter.check @@ -353,7 +353,7 @@ defined class Term scala> def f(e: Exp) = e match { // non-exhaustive warning here case _:Fact => 3 } -:22: warning: match may not be exhaustive. +:18: warning: match may not be exhaustive. It would fail on the following inputs: Exp(), Term() def f(e: Exp) = e match { // non-exhaustive warning here ^ diff --git a/test/files/run/repl-classbased.check b/test/files/run/repl-classbased.check new file mode 100644 index 0000000000..e11fc170e5 --- /dev/null +++ b/test/files/run/repl-classbased.check @@ -0,0 +1,23 @@ + +scala> case class K(s: String) +defined class K + +scala> class C { implicit val k: K = K("OK?"); override def toString = s"C($k)" } +defined class C + +scala> val c = new C +c: C = C(K(OK?)) + +scala> import c.k +import c.k + +scala> implicitly[K] +res0: K = K(OK?) + +scala> val k = 42 +k: Int = 42 + +scala> k // was K(OK?) +res1: Int = 42 + +scala> :quit diff --git a/test/files/run/repl-classbased.scala b/test/files/run/repl-classbased.scala new file mode 100644 index 0000000000..595e123159 --- /dev/null +++ b/test/files/run/repl-classbased.scala @@ -0,0 +1,22 @@ + +import scala.tools.partest.ReplTest +import scala.tools.nsc.Settings + +//SI-9740 +object Test extends ReplTest { + override def transformSettings(s: Settings): Settings = { + s.Yreplclassbased.value = true + s + } + + def code = + """ +case class K(s: String) +class C { implicit val k: K = K("OK?"); override def toString = s"C($k)" } +val c = new C +import c.k +implicitly[K] +val k = 42 +k // was K(OK?) + """ +} diff --git a/test/files/run/repl-javap-app.check b/test/files/run/repl-javap-app.check index bace9534da..e69de29bb2 100644 --- a/test/files/run/repl-javap-app.check +++ b/test/files/run/repl-javap-app.check @@ -1,60 +0,0 @@ -#partest java6 -Welcome to Scala -Type in expressions for evaluation. Or try :help. - -scala> :javap -app MyApp$ -public final void delayedEndpoint$MyApp$1(); - Code: - Stack=2, Locals=1, Args_size=1 - 0: getstatic #XX; //Field scala/Console$.MODULE$:Lscala/Console$; - 3: ldc #XX; //String Hello, delayed world. - 5: invokevirtual #XX; //Method scala/Console$.println:(Ljava/lang/Object;)V - 8: return - LocalVariableTable: - Start Length Slot Name Signature - 0 9 0 this LMyApp$; - -scala> :quit -#partest java7 -Welcome to Scala -Type in expressions for evaluation. Or try :help. - -scala> :javap -app MyApp$ - public final void delayedEndpoint$MyApp$1(); - flags: ACC_PUBLIC, ACC_FINAL - Code: - stack=2, locals=1, args_size=1 - 0: getstatic #XX // Field scala/Console$.MODULE$:Lscala/Console$; - 3: ldc #XX // String Hello, delayed world. - 5: invokevirtual #XX // Method scala/Console$.println:(Ljava/lang/Object;)V - 8: return - LocalVariableTable: - Start Length Slot Name Signature - 0 9 0 this LMyApp$; - LineNumberTable: - line 5: 0 -} - -scala> :quit -#partest java8 -Welcome to Scala -Type in expressions for evaluation. Or try :help. - -scala> :javap -app MyApp$ - public final void delayedEndpoint$MyApp$1(); - descriptor: ()V - flags: ACC_PUBLIC, ACC_FINAL - Code: - stack=2, locals=1, args_size=1 - 0: getstatic #XX // Field scala/Console$.MODULE$:Lscala/Console$; - 3: ldc #XX // String Hello, delayed world. - 5: invokevirtual #XX // Method scala/Console$.println:(Ljava/lang/Object;)V - 8: return - LocalVariableTable: - Start Length Slot Name Signature - 0 9 0 this LMyApp$; - LineNumberTable: - line 5: 0 -} - -scala> :quit diff --git a/test/files/run/repl-javap-app.scala b/test/files/run/repl-javap-app.scala index ad6076c2d5..f7e3baa2a1 100644 --- a/test/files/run/repl-javap-app.scala +++ b/test/files/run/repl-javap-app.scala @@ -8,14 +8,11 @@ object MyApp extends App { object Test extends ReplTest { def code = ":javap -app MyApp$" - override def welcoming = true - - // The constant pool indices are not the same for GenASM / GenBCode, so - // replacing the exact numbers by XX. - lazy val hasConstantPoolRef = """(.*)(#\d\d)(.*)""".r - - override def normalize(s: String) = s match { - case hasConstantPoolRef(start, ref, end) => start + "#XX" + end - case _ => super.normalize(s) + override def show() = { + val coded = "Code:" + val strung = "String Hello, delayed world." + val lines = eval().toList + assert (lines.count(s => s.endsWith(coded)) == 1) + assert (lines.count(s => s.endsWith(strung)) == 1) } } diff --git a/test/files/run/t7319.check b/test/files/run/t7319.check index 4d8429e8f2..31923e7119 100644 --- a/test/files/run/t7319.check +++ b/test/files/run/t7319.check @@ -15,21 +15,21 @@ warning: there was one feature warning; re-run with -feature for details convert: [F[X <: F[X]]](builder: F[_ <: F[_]])Int scala> convert(Some[Int](0)) -:16: error: no type parameters for method convert: (builder: F[_ <: F[_]])Int exist so that it can be applied to arguments (Some[Int]) +:15: error: no type parameters for method convert: (builder: F[_ <: F[_]])Int exist so that it can be applied to arguments (Some[Int]) --- because --- argument expression's type is not compatible with formal parameter type; found : Some[Int] required: ?F[_$1] forSome { type _$1 <: ?F[_$2] forSome { type _$2 } } convert(Some[Int](0)) ^ -:16: error: type mismatch; +:15: error: type mismatch; found : Some[Int] required: F[_ <: F[_]] convert(Some[Int](0)) ^ scala> Range(1,2).toArray: Seq[_] -:15: error: polymorphic expression cannot be instantiated to expected type; +:14: error: polymorphic expression cannot be instantiated to expected type; found : [B >: Int]Array[B] required: Seq[_] Range(1,2).toArray: Seq[_] -- cgit v1.2.3