Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stackoverflow during scala script compile #12485

Closed
philwalk opened this issue May 14, 2021 · 2 comments · Fixed by #12488
Closed

stackoverflow during scala script compile #12485

philwalk opened this issue May 14, 2021 · 2 comments · Fixed by #12488
Assignees
Milestone

Comments

@philwalk
Copy link
Contributor

philwalk commented May 14, 2021

Compiler version

Scala compiler version 3.0.1-RC1-bin-SNAPSHOT-git-c415033 -- Copyright 2002-2021, LAMP/EPFL

Minimized code

I'm in the process of reducing my 300+ line script to a minimal source that reproduces the problem.

In the meantime, maybe someone sees what the problem is from the stack dump. Here's the relevant section showing line 809 of Space.scala

793   private def exhaustivityCheckable(sel: Tree): Boolean = {
794     // Possible to check everything, but be compatible with scalac by default
795     def isCheckable(tp: Type): Boolean =
796       !tp.hasAnnotation(defn.UncheckedAnnot) && {
797         val tpw = tp.widen.dealias
798         val classSym = tpw.classSymbol
799         ctx.settings.YcheckAllPatmat.value ||
800         classSym.is(Sealed) ||
801         tpw.isInstanceOf[OrType] ||
802         (tpw.isInstanceOf[AndType] && {
803           val and = tpw.asInstanceOf[AndType]
804           isCheckable(and.tp1) || isCheckable(and.tp2)
805         }) ||
806         tpw.isRef(defn.BooleanClass) ||
807         classSym.isAllOf(JavaEnumTrait) ||
808         (defn.isProductSubType(tpw) && classSym.is(Case)
809            && productSelectorTypes(tpw, sel.srcPos).exists(isCheckable(_)))
810       }
811 
812     val res = isCheckable(sel.tpe)
813     debug.println(s"exhaustivity checkable: ${sel.show} = $res")
814     res
815   }

Output (click arrow to expand)

$ ssrc/showTkacctHist.sc
java.lang.StackOverflowError while compiling C:\opt\ue\ssrc\showTkacctHist.sc
Exception in thread "main" java.lang.StackOverflowError
        at dotty.tools.dotc.core.Types$Type.findMember(Types.scala:882)
        at dotty.tools.dotc.core.Types$Type.memberBasedOnFlags(Types.scala:666)
        at dotty.tools.dotc.core.Types$Type.member(Types.scala:650)
        at dotty.tools.dotc.typer.Applications$.extractorMember(Applications.scala:47)
        at dotty.tools.dotc.typer.Applications$.extractorMemberType(Applications.scala:50)
        at dotty.tools.dotc.typer.Applications$.$anonfun$2(Applications.scala:116)
        at dotty.tools.dotc.typer.Applications$.$anonfun$adapted$1(Applications.scala:116)
        at scala.collection.Iterator$$anon$9.next(Iterator.scala:575)
        at scala.collection.Iterator$$anon$11.hasNext(Iterator.scala:628)
        at scala.collection.immutable.List.prependedAll(List.scala:152)
        at scala.collection.IterableOnceOps.toList(IterableOnce.scala:1251)
        at scala.collection.IterableOnceOps.toList$(IterableOnce.scala:1251)
        at scala.collection.AbstractIterator.toList(Iterator.scala:1288)
        at dotty.tools.dotc.typer.Applications$.productSelectorTypes(Applications.scala:117)
        at dotty.tools.dotc.transform.patmat.SpaceEngine.isCheckable$1(Space.scala:809)
        at dotty.tools.dotc.transform.patmat.SpaceEngine.isCheckable$2$$anonfun$1(Space.scala:809)
        at scala.collection.immutable.List.exists(List.scala:395)
        at dotty.tools.dotc.transform.patmat.SpaceEngine.isCheckable$1(Space.scala:809)
        at dotty.tools.dotc.transform.patmat.SpaceEngine.isCheckable$2$$anonfun$1(Space.scala:809)
        at scala.collection.immutable.List.exists(List.scala:395)
        at dotty.tools.dotc.transform.patmat.SpaceEngine.isCheckable$1(Space.scala:809)
        at dotty.tools.dotc.transform.patmat.SpaceEngine.isCheckable$2$$anonfun$1(Space.scala:809)
        at scala.collection.immutable.List.exists(List.scala:395)
        at dotty.tools.dotc.transform.patmat.SpaceEngine.isCheckable$1(Space.scala:809)
        at dotty.tools.dotc.transform.patmat.SpaceEngine.isCheckable$2$$anonfun$1(Space.scala:809)
        at scala.collection.immutable.List.exists(List.scala:395)
        at dotty.tools.dotc.transform.patmat.SpaceEngine.isCheckable$1(Space.scala:809)
        at dotty.tools.dotc.transform.patmat.SpaceEngine.isCheckable$2$$anonfun$1(Space.scala:809)
        at scala.collection.immutable.List.exists(List.scala:395)
        at dotty.tools.dotc.transform.patmat.SpaceEngine.isCheckable$1(Space.scala:809)
        at dotty.tools.dotc.transform.patmat.SpaceEngine.isCheckable$2$$anonfun$1(Space.scala:809)
        at scala.collection.immutable.List.exists(List.scala:395)
        at dotty.tools.dotc.transform.patmat.SpaceEngine.isCheckable$1(Space.scala:809)
<snip>
@liufengyun
Copy link
Contributor

@philwalk It seems related to some case class definitions of the form:

case class A(a: A)

@philwalk
Copy link
Contributor Author

philwalk commented May 15, 2021

@philwalk It seems related to some case class definitions of the form:

case class A(a: A)

I have a case class that looks similar called Snapshot. Here's a fairly small file that fails to compile.

#!/opt/scala3/bin/scala

import java.nio.file.{Files, Paths, Path}
import scala.collection.mutable.Queue

object ShowTkacctHist3 {
  case class Owned(bought: Snapshot, sold: Snapshot)
  case class ItemData(datestr: String, qty: Long)
  case class Snapshot(datestr: String, qty: Long, prev: Snapshot){
    assert(datestr.isEmpty || Option(prev) != None) // to insure prev is never null, except in dummySnapshot
    def contiguousWithPrev: Boolean = {
      if (Option(prev) == None){
        sys.error(s"internal error: dummySnapshot null exposed")
      }
      contiguous(prev, this)
    }
  }
  object Snapshot {
    var prevSnap = dummySnapshot
    def apply(idata: ItemData): Snapshot = {
      val newA = new Snapshot(idata.datestr, idata.qty, prevSnap)
      prevSnap = newA
      newA
    }
  }

  def collectSections(dayItems: Seq[Snapshot]) = {
    var work = Queue(dayItems:_*)
    var sectionTicker = ""
    var sections = Vector.empty[Owned]
    while (work.nonEmpty) {
      val section = work.dequeueWhile {
        case it if ! it.contiguousWithPrev && sectionTicker.isEmpty =>
          sectionTicker = it.datestr
          true
        case it if it.contiguousWithPrev =>
          true
        case _ =>
          false
      }
      sectionTicker = ""
      val first = section.head
      val last = section.last
      if( first.datestr.nonEmpty ){
        sections :+= Owned(first, last)
      }
    }
    sections
  }

  def readItems(infile: String): Seq[Snapshot] = {
    var colnames = ""
    val lines = scala.io.Source.fromFile(infile).getLines.filter { _.trim.nonEmpty }
    var timestamp = ""
    var itemData = Vector.empty[ItemData]
    for (line <- lines) do
      line match
      case str if str.startsWith("#") =>
        timestamp = str.drop(1).trim
      case itemstr =>
        itemData :+= ItemData(timestamp, 0L)

    // convert to Snapshot items
    var items = Vector.empty[Snapshot]
    var prevData = DummyItem
    for (idata <- itemData ) {
      val it = Snapshot.apply(idata)
      items :+= it
      prevData = idata
    }
    items
  }

  def contiguous(prev: Snapshot, next: Snapshot): Boolean = {
    if (prev == dummySnapshot){
      false
    } else {
      prev != next
    }
  }

  lazy val DummyItem = ItemData("", 0L)
  lazy val dummySnapshot = new Snapshot("", 0L, null) // null only permitted in dummySnapshot
}

liufengyun added a commit to dotty-staging/dotty that referenced this issue May 15, 2021
liufengyun added a commit that referenced this issue May 17, 2021
Fix #12485: Avoid cycles in testing feasibility of exhaustivity check
dwijnand added a commit to dwijnand/scala3 that referenced this issue Jul 8, 2021
Fixes scala#13003, by refixing scala#12485 (PR scala#12488).

Part of the issue is that isCheckable behaves differently under
-Ycheck-all-patmat and our tests only run under that flag.  So for
starters I added a test variant where that flag isn't used.  I'd like to
understand why that flag exists to see if we could remove it from
guarding the logic and the tests.
dwijnand added a commit to dwijnand/scala3 that referenced this issue Jul 9, 2021
Fixes scala#13003, by refixing scala#12485 (PR scala#12488).

Part of the issue is that isCheckable behaves differently under
-Ycheck-all-patmat and our tests only run under that flag.  So for
starters I added a test variant where that flag isn't used.  I'd like to
understand why that flag exists to see if we could remove it from
guarding the logic and the tests.

Also make sure that any patmat test that throws an exception fails the
test...
BarkingBad pushed a commit to BarkingBad/dotty that referenced this issue Jul 23, 2021
Fixes scala#13003, by refixing scala#12485 (PR scala#12488).

Part of the issue is that isCheckable behaves differently under
-Ycheck-all-patmat and our tests only run under that flag.  So for
starters I added a test variant where that flag isn't used.  I'd like to
understand why that flag exists to see if we could remove it from
guarding the logic and the tests.

Also make sure that any patmat test that throws an exception fails the
test...
@Kordyjan Kordyjan added this to the 3.0.1 milestone Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants