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

compiler throws AssertionError when Product Match zero-arity #13960

Closed
xuwei-k opened this issue Nov 16, 2021 · 3 comments · Fixed by #14029
Closed

compiler throws AssertionError when Product Match zero-arity #13960

xuwei-k opened this issue Nov 16, 2021 · 3 comments · Fixed by #14029

Comments

@xuwei-k
Copy link
Contributor

xuwei-k commented Nov 16, 2021

Compiler version

  • 3.1.2-RC1-bin-20211115-f215817-NIGHTLY
  • 3.1.1-RC1
  • 3.1.0
  • 3.0.2

Minimized code

class A() extends Product {
  override def canEqual(that: Any) = true
  override def productArity = 0
  override def productElement(n: Int) = null
}

object A {
  def unapply(a: A): A = a
}

object Main {
  (new A) match {
    case A() =>
  }
}

Output

[error] ## Exception when compiling 1 sources to /Users/kenji/product-zero-unapply/target/scala-3.1.1-RC1/classes
[error] java.lang.AssertionError: assertion failed
[error] scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:11)
[error] dotty.tools.dotc.transform.PatternMatcher$Translator.unapplyPlan$1$$anonfun$2(PatternMatcher.scala:348)
[error] dotty.tools.dotc.transform.PatternMatcher$Translator.letAbstract(PatternMatcher.scala:107)
[error] dotty.tools.dotc.transform.PatternMatcher$Translator.unapplyPlan$1(PatternMatcher.scala:366)
[error] dotty.tools.dotc.transform.PatternMatcher$Translator.patternPlan(PatternMatcher.scala:401)
[error] dotty.tools.dotc.transform.PatternMatcher$Translator.caseDefPlan(PatternMatcher.scala:437)
[error] dotty.tools.dotc.transform.PatternMatcher$Translator.matchPlan$$anonfun$1$$anonfun$1(PatternMatcher.scala:444)
[error] scala.collection.immutable.List.foldRight(List.scala:352)
[error] dotty.tools.dotc.transform.PatternMatcher$Translator.matchPlan$$anonfun$1(PatternMatcher.scala:444)
[error] dotty.tools.dotc.transform.PatternMatcher$Translator.letAbstract(PatternMatcher.scala:107)
[error] dotty.tools.dotc.transform.PatternMatcher$Translator.matchPlan(PatternMatcher.scala:445)
[error] dotty.tools.dotc.transform.PatternMatcher$Translator.translateMatch(PatternMatcher.scala:1022)
[error] dotty.tools.dotc.transform.PatternMatcher.transformMatch(PatternMatcher.scala:41)
[error] dotty.tools.dotc.transform.MegaPhase.goMatch(MegaPhase.scala:779)
[error] dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:369)
[error] dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:429)
[error] dotty.tools.dotc.transform.MegaPhase.transformStat$1(MegaPhase.scala:439)
[error] dotty.tools.dotc.transform.MegaPhase.recur$1(MegaPhase.scala:442)
[error] dotty.tools.dotc.transform.MegaPhase.recur$1(MegaPhase.scala:442)
[error] dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:442)
[error] dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:362)
[error] dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:429)
[error] dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:256)
[error] dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:427)
[error] dotty.tools.dotc.transform.MegaPhase.transformStat$1(MegaPhase.scala:437)
[error] dotty.tools.dotc.transform.MegaPhase.recur$1(MegaPhase.scala:442)
[error] dotty.tools.dotc.transform.MegaPhase.recur$1(MegaPhase.scala:442)
[error] dotty.tools.dotc.transform.MegaPhase.recur$1(MegaPhase.scala:442)
[error] dotty.tools.dotc.transform.MegaPhase.recur$1(MegaPhase.scala:442)
[error] dotty.tools.dotc.transform.MegaPhase.recur$1(MegaPhase.scala:442)
[error] dotty.tools.dotc.transform.MegaPhase.recur$1(MegaPhase.scala:442)
[error] dotty.tools.dotc.transform.MegaPhase.recur$1(MegaPhase.scala:442)
[error] dotty.tools.dotc.transform.MegaPhase.recur$1(MegaPhase.scala:442)
[error] dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:442)
[error] dotty.tools.dotc.transform.MegaPhase.mapPackage$1(MegaPhase.scala:382)
[error] dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:385)
[error] dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:429)
[error] dotty.tools.dotc.transform.MegaPhase.transformUnit(MegaPhase.scala:448)
[error] dotty.tools.dotc.transform.MegaPhase.run(MegaPhase.scala:460)
[error] dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:308)
[error] scala.collection.immutable.List.map(List.scala:246)
[error] dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:309)
[error] dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:261)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error] scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323)
[error] dotty.tools.dotc.Run.runPhases$1(Run.scala:272)
[error] dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:280)
[error] scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
[error] dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:68)
[error] dotty.tools.dotc.Run.compileUnits(Run.scala:289)
[error] dotty.tools.dotc.Run.compileSources(Run.scala:222)
[error] dotty.tools.dotc.Run.compile(Run.scala:206)
[error] dotty.tools.dotc.Driver.doCompile(Driver.scala:39)
[error] dotty.tools.xsbt.CompilerBridgeDriver.run(CompilerBridgeDriver.java:88)
[error] dotty.tools.xsbt.CompilerBridge.run(CompilerBridge.java:22)
[error] sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:91)
[error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$7(MixedAnalyzingCompiler.scala:192)
[error] scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
[error] sbt.internal.inc.MixedAnalyzingCompiler.timed(MixedAnalyzingCompiler.scala:247)
[error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4(MixedAnalyzingCompiler.scala:182)
[error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4$adapted(MixedAnalyzingCompiler.scala:163)
[error] sbt.internal.inc.JarUtils$.withPreviousJar(JarUtils.scala:239)
[error] sbt.internal.inc.MixedAnalyzingCompiler.compileScala$1(MixedAnalyzingCompiler.scala:163)
[error] sbt.internal.inc.MixedAnalyzingCompiler.compile(MixedAnalyzingCompiler.scala:210)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1(IncrementalCompilerImpl.scala:528)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1$adapted(IncrementalCompilerImpl.scala:528)
[error] sbt.internal.inc.Incremental$.$anonfun$apply$5(Incremental.scala:175)
[error] sbt.internal.inc.Incremental$.$anonfun$apply$5$adapted(Incremental.scala:173)
[error] sbt.internal.inc.Incremental$$anon$2.run(Incremental.scala:459)
[error] sbt.internal.inc.IncrementalCommon$CycleState.next(IncrementalCommon.scala:116)
[error] sbt.internal.inc.IncrementalCommon$$anon$1.next(IncrementalCommon.scala:56)
[error] sbt.internal.inc.IncrementalCommon$$anon$1.next(IncrementalCommon.scala:52)
[error] sbt.internal.inc.IncrementalCommon.cycle(IncrementalCommon.scala:263)
[error] sbt.internal.inc.Incremental$.$anonfun$incrementalCompile$8(Incremental.scala:414)
[error] sbt.internal.inc.Incremental$.withClassfileManager(Incremental.scala:501)
[error] sbt.internal.inc.Incremental$.incrementalCompile(Incremental.scala:401)
[error] sbt.internal.inc.Incremental$.apply(Incremental.scala:167)
[error] sbt.internal.inc.IncrementalCompilerImpl.compileInternal(IncrementalCompilerImpl.scala:528)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileIncrementally$1(IncrementalCompilerImpl.scala:482)
[error] sbt.internal.inc.IncrementalCompilerImpl.handleCompilationError(IncrementalCompilerImpl.scala:332)
[error] sbt.internal.inc.IncrementalCompilerImpl.compileIncrementally(IncrementalCompilerImpl.scala:420)
[error] sbt.internal.inc.IncrementalCompilerImpl.compile(IncrementalCompilerImpl.scala:137)
[error] sbt.Defaults$.compileIncrementalTaskImpl(Defaults.scala:2357)
[error] sbt.Defaults$.$anonfun$compileIncrementalTask$2(Defaults.scala:2314)
[error] sbt.internal.io.Retry$.apply(Retry.scala:46)
[error] sbt.internal.io.Retry$.apply(Retry.scala:28)
[error] sbt.internal.io.Retry$.apply(Retry.scala:23)
[error] sbt.internal.server.BspCompileTask$.compute(BspCompileTask.scala:31)
[error] sbt.Defaults$.$anonfun$compileIncrementalTask$1(Defaults.scala:2310)
[error] scala.Function1.$anonfun$compose$1(Function1.scala:49)
[error] sbt.internal.util.$tilde$greater.$anonfun$$u2219$1(TypeFunctions.scala:62)
[error] sbt.std.Transform$$anon$4.work(Transform.scala:68)
[error] sbt.Execute.$anonfun$submit$2(Execute.scala:282)
[error] sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:23)
[error] sbt.Execute.work(Execute.scala:291)
[error] sbt.Execute.$anonfun$submit$1(Execute.scala:282)
[error] sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:265)
[error] sbt.CompletionService$$anon$2.call(CompletionService.scala:64)
[error] java.util.concurrent.FutureTask.run(FutureTask.java:266)
[error] java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
[error] java.util.concurrent.FutureTask.run(FutureTask.java:266)
[error] java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[error] java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[error] java.lang.Thread.run(Thread.java:748)
@dwijnand
Copy link
Member

dwijnand commented Nov 19, 2021

See also the variant in #13977, which uses EmptyTuple.

@SethTisue
Copy link
Member

SethTisue commented Dec 2, 2021

It's documented that product matches must be nonzero arity; https://docs.scala-lang.org/scala3/reference/changed-features/pattern-matching.html specifies "N > 0" and did so even when first written (#2565 from 2017).

So it wouldn't be wrong to reject the code (with a proper error message instead of a crash, of course). You can use a boolean match instead of a product match to handle the arity-0 case.

But also, why not simply allow the arity-0 case? It seems harmless to allow it as far as I can see, and allowing it would be more uniform. (And might assist e.g. a code generator, which currently would need to handle the 0 case specially.)

@SethTisue
Copy link
Member

#14029 just does the minimal fix to prevent the crash, leaving the question open of whether the 0-arity case could or should be supported in the future.

@Kordyjan Kordyjan added this to the 3.1.2 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.

4 participants