Skip to content

StackOverflowError when using implicit class compiled with Scala 3 in Scala 2 #13105

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

Open
jadenPete opened this issue Jun 3, 2025 · 1 comment

Comments

@jadenPete
Copy link

Reproduction steps

Scala 2 version: 2.13.16
Scala 3 version: 3.6.3

Please let me know if scala/scala3 is a better place to post this.

  1. Compile the following with Scala 3:
package foo

package object bar {
  implicit class EnrichedNumberOption(private val number: Option[Int]) {
    def +(other: Option[Int]): Option[Int] = number.flatMap(number => other.map(number + _))
  }
}
  1. Compile the following with Scala 2:
package foo.bar

object Main {
  None + None
}
  1. Observe the following exception:
java.lang.StackOverflowError
scala.reflect.internal.Symbols$Symbol.isTopLevel(Symbols.scala:1048)
scala.reflect.internal.Symbols$ClassSymbol.associatedFile(Symbols.scala:3442)
scala.reflect.internal.Symbols$Symbol.isCoDefinedWith(Symbols.scala:2346)
scala.reflect.internal.Symbols$Symbol.$anonfun$companionClass$1(Symbols.scala:2385)
scala.reflect.internal.Symbols$Symbol.$anonfun$companionClass$1$adapted(Symbols.scala:2385)
scala.reflect.internal.Symbols$Symbol.filter(Symbols.scala:2061)
scala.reflect.internal.Symbols$Symbol.suchThat(Symbols.scala:2065)
scala.reflect.internal.Symbols$Symbol.companionClass(Symbols.scala:2385)
scala.reflect.internal.Symbols$ModuleClassSymbol.linkedClassOfClass(Symbols.scala:3549)
scala.tools.nsc.typechecker.Infer$Inferencer.isProperSubClassOrObject(Infer.scala:923)
scala.tools.nsc.typechecker.Infer$Inferencer.isProperSubClassOrObject(Infer.scala:923)
scala.tools.nsc.typechecker.Infer$Inferencer.isProperSubClassOrObject(Infer.scala:923)
...

Problem

I'd expect the Scala 2 code to compile.

@som-snytt
Copy link

It works if the operator is not +.

This is an example where it would have been convenient to have the directives first.

This doesn't seem to work, using local Scala 2:

skalac -d out -cp "out;../../projects/dotty/library/target/scala-3.7.1/scala3-library_3-3.7.2-RC1-bin-SNAPSHOT-nonbootstrapped.jar" -Ytasty-reader main.scala
main.scala:10: error: value % is not a member of Option[Int]

I did not use my sabbatical year to figure out why.

Sample working operator:

//> using options -Ytasty-reader
//> using dep org.scala-lang:scala3-library_3:3.7.1
///> using dep org.scala-lang:scala3-library_3:3.6.4
package foo.bar

// masking imports allows using `+`
import scala.Predef.{any2stringadd => _, _}

object Main extends App {
  println {
    //None + None
    //Option(42) + Option(27)
    Option(42) % Option(27)
  }
}

The masking import works for the OP, no idea why.

What also works is "excluding" that conversion using -Xsource-features:

//> using options -Ytasty-reader -Xsource:3 -Xsource-features:any2stringadd

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants