Skip to content

Commit

Permalink
Silence outer pointer warnings in class-based REPL
Browse files Browse the repository at this point in the history
Case classes, such as final case classes nested within other classes,
lose their outer pointer which makes their equality lie (scala/bug#4440):

    scala> class Outer { final case class Inner(n: Int) }
    warning: there was one unchecked warning; for details, enable `:setting -unchecked' or `:replay -unchecked'
    defined class Outer

    scala> val o1, o2 = new Outer
    o1: Outer = Outer@627bcd7e
    o2: Outer = Outer@70543cae

    scala> new o1.Inner(1) == new o2.Inner(1)
    res0: Boolean = true

vs

    scala> class Outer { case class Inner(n: Int) }
    defined class Outer

    scala> val o1, o2 = new Outer
    o1: Outer = Outer@77ba583
    o2: Outer = Outer@5613247e

    scala> new o1.Inner(1) == new o2.Inner(1)
    res0: Boolean = false

This isn't a problem in the REPL even with its class-based wrappers as
there is only ever 1 instance of (each) wrapper class.
  • Loading branch information
dwijnand authored and retronym committed Mar 24, 2020
1 parent 063b7f2 commit daa40b8
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging {
// this also includes methods and (possibly nested) objects inside of methods.
def definedInStaticLocation(tp: Type): Boolean = {
def isStatic(tp: Type): Boolean =
if (tp == NoType || tp.typeSymbol.isPackageClass || tp == NoPrefix) true
if (tp == NoType || tp.typeSymbol.isPackageClass || tp == NoPrefix || nme.isReplWrapperName(tp.typeSymbol.name)) true
else if (tp.typeSymbol.isModuleClass) isStatic(tp.prefix)
else false
tp.typeSymbol.owner == tp.prefix.typeSymbol && isStatic(tp.prefix)
Expand Down
14 changes: 14 additions & 0 deletions test/files/run/repl-class-based-outer-pointers.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

scala> sealed abstract class Value; object Value {
final case class Num(value: Double) extends Value
final case class Str(value: String) extends Value
final case class Bool(value: Boolean) extends Value
}
defined class Value
defined object Value

scala> class C { final case class Num(value: Double) } // here it should still warn
warning: there was one unchecked warning; for details, enable `:setting -unchecked' or `:replay -unchecked'
defined class C

scala> :quit
35 changes: 35 additions & 0 deletions test/files/run/repl-class-based-outer-pointers.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import scala.tools.nsc.Settings
import scala.tools.partest.ReplTest

object Test extends ReplTest {
override def transformSettings(s: Settings) = {
s.Yreplclassbased.value = true
s
}

def code = """
|sealed abstract class Value; object Value {
| final case class Num(value: Double) extends Value
| final case class Str(value: String) extends Value
| final case class Bool(value: Boolean) extends Value
|}
|class C { final case class Num(value: Double) } // here it should still warn
|""".stripMargin // scala/bug#11902
}

/* was:
scala> sealed abstract class Value; object Value {
final case class Num(value: Double) extends Value
final case class Str(value: String) extends Value
final case class Bool(value: Boolean) extends Value
}
warning: there were three unchecked warnings; for details, enable `:setting -unchecked' or `:replay -unchecked'
defined class Value
defined object Value
scala> class C { final case class Num(value: Double) } // here it should still warn
warning: there was one unchecked warning; for details, enable `:setting -unchecked' or `:replay -unchecked'
defined class C
*/

0 comments on commit daa40b8

Please sign in to comment.