Skip to content

java.lang.NullPointerException on pattern match in dotty REPL  #4051

Closed
@prayagupa

Description

@prayagupa

Might be more of stackoverflow question not a issues at all but I was playing with dotty REPL with a tuple2 and _._2 works fine

scala> Seq(("Porcupine", 1), ("Floyd", 2), ("Phil Collins", 3)).map(_._2) 
val res0: Seq[Int] = List(1, 2, 3)

But when I pattern match and get the second column it throws a NullPointerException.

scala> Seq(("Porcupine", 1), ("Floyd", 2), ("Phil Collins", 3)).collect {case (name, value) => value } 
Exception in thread "main" java.lang.NullPointerException
	at dotty.tools.dotc.transform.ExpandPrivate.ensurePrivateAccessible(ExpandPrivate.scala:93)
	at dotty.tools.dotc.transform.ExpandPrivate.transformSelect(ExpandPrivate.scala:104)
	at dotty.tools.dotc.transform.MegaPhase.goSelect(MegaPhase.scala:531)
	at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:212)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:364)
	at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:248)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:365)
	at dotty.tools.dotc.transform.MegaPhase.mapDefDef$1(MegaPhase.scala:228)
	at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:231)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:364)
	at dotty.tools.dotc.transform.MegaPhase.transformStat$2(MegaPhase.scala:373)
	at dotty.tools.dotc.transform.MegaPhase.$anonfun$1(MegaPhase.scala:378)
	at scala.collection.immutable.List.mapConserve(List.scala:176)
	at dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:378)
	at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:317)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:365)
	at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:234)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:364)
	at dotty.tools.dotc.transform.MegaPhase.transformStat$2(MegaPhase.scala:373)
	at dotty.tools.dotc.transform.MegaPhase.$anonfun$1(MegaPhase.scala:378)
	at scala.collection.immutable.List.mapConserve(List.scala:176)
	at dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:378)
	at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:317)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:365)
	at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:234)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:364)
	at dotty.tools.dotc.transform.MegaPhase.transformStat$2(MegaPhase.scala:373)
	at dotty.tools.dotc.transform.MegaPhase.$anonfun$1(MegaPhase.scala:378)
	at scala.collection.immutable.List.mapConserve(List.scala:176)
	at dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:378)
	at dotty.tools.dotc.transform.MegaPhase.mapPackage$1(MegaPhase.scala:334)
	at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:337)
	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:365)
	at dotty.tools.dotc.transform.MegaPhase.transformUnit(MegaPhase.scala:384)
	at dotty.tools.dotc.transform.MegaPhase.run(MegaPhase.scala:396)
	at dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:293)
	at scala.collection.immutable.List.map(List.scala:283)
	at dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:295)
	at dotty.tools.dotc.Run.runPhases$4$$anonfun$4(Run.scala:123)
	at scala.compat.java8.JProcedure1.apply(JProcedure1.java:18)
	at scala.compat.java8.JProcedure1.apply(JProcedure1.java:10)
	at scala.collection.IndexedSeqOptimized.foreach(IndexedSeqOptimized.scala:32)
	at scala.collection.IndexedSeqOptimized.foreach$(IndexedSeqOptimized.scala:29)
	at scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:191)
	at dotty.tools.dotc.Run.runPhases$5(Run.scala:136)
	at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:141)
	at scala.compat.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
	at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:88)
	at dotty.tools.dotc.Run.compileUnits(Run.scala:143)
	at dotty.tools.dotc.Run.compileUnits(Run.scala:99)
	at dotty.tools.repl.ReplCompiler.runCompilationUnit(ReplCompiler.scala:188)
	at dotty.tools.repl.ReplCompiler.compile(ReplCompiler.scala:197)
	at dotty.tools.repl.ReplDriver.compile(ReplDriver.scala:223)
	at dotty.tools.repl.ReplDriver.interpret(ReplDriver.scala:196)
	at dotty.tools.repl.ReplDriver.runUntilQuit(ReplDriver.scala:149)
	at dotty.tools.repl.Main$.main(Main.scala:6)
	at dotty.tools.repl.Main.main(Main.scala)

Get the same error with Seq(("Porcupine", 1), ("Floyd", 2), ("Phil Collins", 3)).collect {case x => x._2}.

Tried a bit exploring the reason which is in ExpandPrivate#ensurePrivateAccessible which is line assert(d.symbol.sourceFile != null && isSimilar(d.symbol.sourceFile.path, ctx.owner.sourceFile.path)

  private def ensurePrivateAccessible(d: SymDenotation)(implicit ctx: Context) =
    if (isVCPrivateParamAccessor(d))
      d.ensureNotPrivate.installAfter(thisPhase)
    else if (d.is(PrivateTerm) && !d.owner.is(Package) && d.owner != ctx.owner.lexicallyEnclosingClass) {
      // Paths `p1` and `p2` are similar if they have a common suffix that follows
      // possibly different directory paths. That is, their common suffix extends
      // in both cases either to the start of the path or to a file separator character.
      def isSimilar(p1: String, p2: String): Boolean = {
        var i = p1.length - 1
        var j = p2.length - 1
        while (i >= 0 && j >= 0 && p1(i) == p2(j) && p1(i) != separatorChar) {
          i -= 1
          j -= 1
        }
        (i < 0 || p1(i) == separatorChar) &&
        (j < 0 || p1(j) == separatorChar)
      }

      assert(d.symbol.sourceFile != null &&
             isSimilar(d.symbol.sourceFile.path, ctx.owner.sourceFile.path),
          s"private ${d.symbol.showLocated} in ${d.symbol.sourceFile} accessed from ${ctx.owner.showLocated} in ${ctx.owner.sourceFile}")
      d.ensureNotPrivate.installAfter(thisPhase)
    }

I also tried with simpler pattern match, it does not work.

Seq(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).collect {case x if x % 2 == 0 => (x, 1) }

Don't know what is SymDenotation.symbol or Context.owner. I installed dotty using homebrew and believe it is the built from latest codebase.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions