scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.88k stars 1.06k forks source link

Evaluation of invalid Function crashes Scala #21952

Open jcarbaut opened 4 days ago

jcarbaut commented 4 days ago

Compiler version

3.5.2

Minimized code

When running in scala-cli, the following crashes:

(new Function[(Int, Int), Int] {def apply(a: Int, b: Int): Int = a * b})(2, 3)

Of course, the above code is invalid, there should be a single tuple argument to apply. The unexpected result is that Scala crashes altogether instead of just throwing an exception.

It should be replaced with any of the following, which both work:

(new Function[(Int, Int), Int] {def apply(a: (Int, Int)): Int = a._1 * a._2})(2, 3)
(new Function2[Int, Int, Int] {def apply(a: Int, b: Int): Int = a * b})(2, 3)

Output (click arrow to expand)

```scala unhandled exception while running MegaPhase{crossVersionChecks, firstTransform, checkReentrant, elimPackagePrefixes, cookComments, checkLoopingImplicits, betaReduce, inlineVals, expandSAMs, elimRepeated, refchecks} on rs$line$1 An unhandled exception was thrown in the compiler. Please file a crash report here: https://github.com/scala/scala3/issues/new/choose For non-enriched exceptions, compile with -Xno-enrich-error-messages. while compiling: rs$line$1 during phase: MegaPhase{crossVersionChecks, firstTransform, checkReentrant, elimPackagePrefixes, cookComments, checkLoopingImplicits, betaReduce, inlineVals, expandSAMs, elimRepeated, refchecks} mode: Mode(ImplicitsEnabled,ReadPositions,Interactive) library version: version 2.13.14 compiler version: version 3.5.2 settings: -Xcook-docs true -Xread-docs true -classpath /home/beaver/.my/java/scala3/maven2/org/scala-lang/scala3-library_3/3.5.2/scala3-library_3-3.5.2.jar:/home/beaver/.my/java/scala3/maven2/org/scala-lang/scala-library/2.13.14/scala-library-2.13.14.jar -d Exception in thread "main" java.lang.UnsupportedOperationException: tail of empty list at scala.collection.immutable.Nil$.tail(List.scala:665) at scala.collection.immutable.Nil$.tail(List.scala:662) at dotty.tools.dotc.core.Substituters$.substSym(Substituters.scala:87) at dotty.tools.dotc.core.Types$Type.substSym(Types.scala:1942) at dotty.tools.dotc.ast.TreeTypeMap$$anon$2.apply(TreeTypeMap.scala:75) at dotty.tools.dotc.ast.TreeTypeMap.mapType(TreeTypeMap.scala:76) at dotty.tools.dotc.ast.TreeTypeMap.transform(TreeTypeMap.scala:110) at dotty.tools.dotc.transform.BetaReduce$.reduceApplication(BetaReduce.scala:151) at dotty.tools.dotc.transform.BetaReduce$.recur$1(BetaReduce.scala:82) at dotty.tools.dotc.transform.BetaReduce$.apply(BetaReduce.scala:95) at dotty.tools.dotc.transform.BetaReduce.transformApply(BetaReduce.scala:44) at dotty.tools.dotc.transform.MegaPhase.goApply(MegaPhase.scala:681) at dotty.tools.dotc.transform.MegaPhase.goApply(MegaPhase.scala:682) at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:297) at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:454) at dotty.tools.dotc.transform.MegaPhase.mapValDef$1(MegaPhase.scala:251) at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:256) at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:452) at dotty.tools.dotc.transform.MegaPhase.loop$1(MegaPhase.scala:465) at dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:465) at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:376) at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:454) at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:272) at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:452) at dotty.tools.dotc.transform.MegaPhase.loop$1(MegaPhase.scala:465) at dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:465) at dotty.tools.dotc.transform.MegaPhase.mapPackage$1(MegaPhase.scala:396) at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:399) at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:454) at dotty.tools.dotc.transform.MegaPhase.transformUnit(MegaPhase.scala:481) at dotty.tools.dotc.transform.MegaPhase.run(MegaPhase.scala:493) at dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:380) at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15) at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10) at scala.collection.immutable.List.foreach(List.scala:334) at dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:373) at dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:343) at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15) at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10) at scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323) at dotty.tools.dotc.Run.runPhases$1(Run.scala:336) at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:384) at dotty.tools.dotc.Run.compileUnits$$anonfun$adapted$1(Run.scala:396) at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:69) at dotty.tools.dotc.Run.compileUnits(Run.scala:396) at dotty.tools.dotc.Run.compileUnits(Run.scala:288) at dotty.tools.repl.ReplCompiler.compile(ReplCompiler.scala:88) at dotty.tools.repl.ReplDriver.compile(ReplDriver.scala:321) at dotty.tools.repl.ReplDriver.interpret(ReplDriver.scala:283) at dotty.tools.repl.ReplDriver.loop$1(ReplDriver.scala:196) at dotty.tools.repl.ReplDriver.runUntilQuit$$anonfun$1(ReplDriver.scala:199) at dotty.tools.repl.ReplDriver.withRedirectedOutput(ReplDriver.scala:238) at dotty.tools.repl.ReplDriver.runBody$$anonfun$1(ReplDriver.scala:212) at dotty.tools.runner.ScalaClassLoader$.asContext(ScalaClassLoader.scala:80) at dotty.tools.repl.ReplDriver.runBody(ReplDriver.scala:212) at dotty.tools.repl.ReplDriver.runUntilQuit(ReplDriver.scala:199) at dotty.tools.repl.ReplDriver.tryRunning(ReplDriver.scala:136) at dotty.tools.repl.Main$.main(Main.scala:7) at dotty.tools.repl.Main.main(Main.scala) ```

Note

Note also that simply creating the function only throws an exception, without crashing: ```Scala new Function[(Int, Int), Int] {def apply(a: Int, b: Int): Int = a * b} ``` Output: ```scala -- Error: ---------------------------------------------------------------------------------------------------------------------------------- 1 |new Function[(Int, Int), Int] {def apply(a: Int, b: Int): Int = a * b} |^ |object creation impossible, since def apply(v1: T1): R in trait Function1 in package scala is not defined 1 error found ```
Gedochao commented 3 days ago
scala-cli compile --script-snippet '(new Function[(Int, Int), Int] {def apply(a: Int, b: Int): Int = a * b})(2, 3)'

Here's the output when compiled outside of the REPL:

```scala -- Error: /var/folders/5n/_ggj7kk93czdt_n0jzrk8s780000gn/T/14507058402592798626/.scala-build/14507058402592798626_22f9a8571a-571f19b3f1/src_generated/main/snippet.scala:7:1 7 |(new Function[(Int, Int), Int] {def apply(a: Int, b: Int): Int = a * b})(2, 3) | ^ |object creation impossible, since def apply(v1: T1): R in trait Function1 in package scala is not defined unhandled exception while running MegaPhase{crossVersionChecks, firstTransform, checkReentrant, elimPackagePrefixes, cookComments, checkLoopingImplicits, betaReduce, inlineVals, expandSAMs, elimRepeated, refchecks} on /var/folders/5n/_ggj7kk93czdt_n0jzrk8s780000gn/T/14507058402592798626/.scala-build/14507058402592798626_22f9a8571a-571f19b3f1/src_generated/main/snippet.scala An unhandled exception was thrown in the compiler. Please file a crash report here: https://github.com/scala/scala3/issues/new/choose For non-enriched exceptions, compile with -Xno-enrich-error-messages. while compiling: /var/folders/5n/_ggj7kk93czdt_n0jzrk8s780000gn/T/14507058402592798626/.scala-build/14507058402592798626_22f9a8571a-571f19b3f1/src_generated/main/snippet.scala during phase: MegaPhase{crossVersionChecks, firstTransform, checkReentrant, elimPackagePrefixes, cookComments, checkLoopingImplicits, betaReduce, inlineVals, expandSAMs, elimRepeated, refchecks} mode: Mode(ImplicitsEnabled) library version: version 2.13.14 compiler version: version 3.5.1 settings: -classpath /Users/pchabelski/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.5.1/scala3-library_3-3.5.1.jar:/Users/pchabelski/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.14/scala-library-2.13.14.jar -d /var/folders/5n/_ggj7kk93czdt_n0jzrk8s780000gn/T/14507058402592798626/.scala-build/14507058402592798626_22f9a8571a-571f19b3f1/classes/main -explain true -sourceroot /var/folders/5n/_ggj7kk93czdt_n0jzrk8s780000gn/T/14507058402592798626 Exception in thread "main" java.lang.UnsupportedOperationException: tail of empty list at scala.collection.immutable.Nil$.tail(List.scala:665) at scala.collection.immutable.Nil$.tail(List.scala:662) at dotty.tools.dotc.core.Substituters$.substSym(Substituters.scala:87) at dotty.tools.dotc.core.Types$Type.substSym(Types.scala:1941) at dotty.tools.dotc.ast.TreeTypeMap$$anon$2.apply(TreeTypeMap.scala:75) at dotty.tools.dotc.ast.TreeTypeMap.mapType(TreeTypeMap.scala:76) at dotty.tools.dotc.ast.TreeTypeMap.transform(TreeTypeMap.scala:110) at dotty.tools.dotc.transform.BetaReduce$.reduceApplication(BetaReduce.scala:151) at dotty.tools.dotc.transform.BetaReduce$.recur$1(BetaReduce.scala:82) at dotty.tools.dotc.transform.BetaReduce$.apply(BetaReduce.scala:95) at dotty.tools.dotc.transform.BetaReduce.transformApply(BetaReduce.scala:44) at dotty.tools.dotc.transform.MegaPhase.goApply(MegaPhase.scala:681) at dotty.tools.dotc.transform.MegaPhase.goApply(MegaPhase.scala:682) at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:297) at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:454) at dotty.tools.dotc.transform.MegaPhase.loop$1(MegaPhase.scala:465) at dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:465) at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:376) at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:454) at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:272) at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:452) at dotty.tools.dotc.transform.MegaPhase.loop$1(MegaPhase.scala:465) at dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:465) at dotty.tools.dotc.transform.MegaPhase.mapPackage$1(MegaPhase.scala:396) at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:399) at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:454) at dotty.tools.dotc.transform.MegaPhase.transformUnit(MegaPhase.scala:481) at dotty.tools.dotc.transform.MegaPhase.run(MegaPhase.scala:493) at dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:380) at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15) at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10) at scala.collection.immutable.List.foreach(List.scala:334) at dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:373) at dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:343) at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15) at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10) at scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323) at dotty.tools.dotc.Run.runPhases$1(Run.scala:336) at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:384) at dotty.tools.dotc.Run.compileUnits$$anonfun$adapted$1(Run.scala:396) at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:69) at dotty.tools.dotc.Run.compileUnits(Run.scala:396) at dotty.tools.dotc.Run.compileSources(Run.scala:282) at dotty.tools.dotc.Run.compile(Run.scala:267) at dotty.tools.dotc.Driver.doCompile(Driver.scala:37) at dotty.tools.dotc.Driver.process(Driver.scala:201) at dotty.tools.dotc.Driver.process(Driver.scala:169) at dotty.tools.dotc.Driver.process(Driver.scala:181) at dotty.tools.dotc.Driver.main(Driver.scala:211) at dotty.tools.dotc.Main.main(Main.scala) ```
Gedochao commented 3 days ago

Labelling as a regression, as it seems this used to not crash pre-3.3.1.

Last good stable version: 3.3.0 First bad stable version: 3.3.1