Skip to content

Commit

Permalink
SI-9740 Repl import fix -Yrepl-class-based
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
som-snytt committed May 2, 2016
1 parent cf38506 commit 86ae2f9
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 92 deletions.
35 changes: 20 additions & 15 deletions src/repl/scala/tools/nsc/interpreter/Imports.scala
Expand Up @@ -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)
}
}
Expand Down Expand Up @@ -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()
Expand All @@ -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
Expand Down
9 changes: 5 additions & 4 deletions src/repl/scala/tools/nsc/interpreter/package.scala
Expand Up @@ -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) _)
}
}
2 changes: 1 addition & 1 deletion test/files/jvm/interpreter.check
Expand Up @@ -353,7 +353,7 @@ defined class Term
scala> def f(e: Exp) = e match { // non-exhaustive warning here
case _:Fact => 3
}
<console>:22: warning: match may not be exhaustive.
<console>: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
^
Expand Down
23 changes: 23 additions & 0 deletions 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
22 changes: 22 additions & 0 deletions 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?)
"""
}
60 changes: 0 additions & 60 deletions 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
15 changes: 6 additions & 9 deletions test/files/run/repl-javap-app.scala
Expand Up @@ -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)
}
}
6 changes: 3 additions & 3 deletions test/files/run/t7319.check
Expand Up @@ -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))
<console>:16: error: no type parameters for method convert: (builder: F[_ <: F[_]])Int exist so that it can be applied to arguments (Some[Int])
<console>: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))
^
<console>:16: error: type mismatch;
<console>:15: error: type mismatch;
found : Some[Int]
required: F[_ <: F[_]]
convert(Some[Int](0))
^

scala> Range(1,2).toArray: Seq[_]
<console>:15: error: polymorphic expression cannot be instantiated to expected type;
<console>:14: error: polymorphic expression cannot be instantiated to expected type;
found : [B >: Int]Array[B]
required: Seq[_]
Range(1,2).toArray: Seq[_]
Expand Down

0 comments on commit 86ae2f9

Please sign in to comment.