scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
232 stars 21 forks source link

REPL shadowing broken under `:paste -raw` #12034

Open som-snytt opened 4 years ago

som-snytt commented 4 years ago

reproduction steps

using Scala 2.13.2,

scala> new C
val res0: C = extantC

scala> class C { override def toString = "lineC" }
class C

scala> new C
val res1: C = lineC

scala> :pa -raw
// Entering paste mode (ctrl-D to finish)

class C { override def toString = "rawC" }

// Exiting paste mode, now interpreting.

scala> new C
val res2: C = lineC

scala> :pa -raw
// Entering paste mode (ctrl-D to finish)

package c { class C { override def toString = "rawC" } }

// Exiting paste mode, now interpreting.

scala> new c.C
val res4: c.C = rawC

scala> :pa -raw
// Entering paste mode (ctrl-D to finish)

package c { class C { override def toString = "rawC2" } }

// Exiting paste mode, now interpreting.

scala> new c.C
val res5: c.C = rawC

scala> :reset
Resetting interpreter state.
Forgetting this session history:

new C
class C { override def toString = "lineC" }
new C
new C
new c.C
new c.C

Forgetting all expression results and named terms: $intp
Forgetting defined types: C

scala> new c.C
java.lang.NoClassDefFoundError: c/C
  at java.lang.Class.getDeclaredMethods0(Native Method)
  at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
  at java.lang.Class.privateGetPublicMethods(Class.java:2902)
  at java.lang.Class.getMethods(Class.java:1615)
  at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.evalMethod(IMain.scala:728)
[snip]
Caused by: java.lang.ClassNotFoundException: c.C
  at scala.reflect.internal.util.AbstractFileClassLoader.findClass(AbstractFileClassLoader.scala:71)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
  ... 27 more

scala> :pa -raw
// Entering paste mode (ctrl-D to finish)

package c { class C { override def toString = "rawC2" } }

// Exiting paste mode, now interpreting.

scala> new c.C
val res1: c.C = rawC2

Also,

scala> :pa -raw
// Entering paste mode (ctrl-D to finish)

class C { override def toString = "rawC" }

// Exiting paste mode, now interpreting.

scala> new C
val res1: C = extantC

problem

Apparent shadowing is confusing.

An existing class on the class path is "shadowed" by a class in a line package, because REPL scope is consulted first for import candidates. That makes sense, though it might be nice to warn when a logical class name changes provenance.

A rawly pasted class is hidden by an existing class on the class path. That is probably only an issue for default empty package, so maybe keeping it off the class path would be a feature.

You can't redefine a class with raw paste.

:reset has a hiccup as shown.

Maybe what's needed is class loader management to go along with history management (collecting previously computed values).

Jasper-M commented 4 years ago

Here's another one.

scala> :pa -raw
// Entering paste mode (ctrl-D to finish)

class C

// Exiting paste mode, now interpreting.

scala> new C
val res0: C = C@5cd25b58

scala> :pa -raw
// Entering paste mode (ctrl-D to finish)

class C { def foo = 0 }

// Exiting paste mode, now interpreting.

scala> new C().foo
java.lang.NoSuchMethodError: C.foo()I
  ... 40 elided
SethTisue commented 3 years ago

fwiw I think of :paste -raw as power-user, hackers-only, you're-on-your-own-here stuff. When I use it, I use it exactly once, at the beginning of a REPL session, and then if I need to change something, I restart the REPL.

dwijnand commented 3 years ago

Without :paste and with standard :paste things seem to define as expected, so I amended the title:

scala> class C { override def toString = "lineC" }
class C

scala> new C
val res0: C = lineC

scala> class C { override def toString = "rawC" }
class C

scala> new C
val res1: C = rawC
scala> class C { override def toString = "lineC" }
class C

scala> new C
val res0: C = lineC

scala> :paste
// Entering paste mode (ctrl-D to finish)

class C { override def toString = "pasteC" }

// Exiting paste mode, now interpreting.

class C

scala> new C
val res1: C = pasteC