Skip to content

Compiler crash with custom unapply method #22550

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
road21 opened this issue Feb 7, 2025 · 6 comments · May be fixed by #22699
Open

Compiler crash with custom unapply method #22550

road21 opened this issue Feb 7, 2025 · 6 comments · May be fixed by #22699

Comments

@road21
Copy link
Contributor

road21 commented Feb 7, 2025

Compiler version

3.6.2, 3.6.3 NEXT

Minimized code

case class Data[A]()

trait TCl[A, B]

object Matches:
  def unapply[A](adt: Data[?])[B](using
      ft: TCl[A, B]
  ): Option[Data[A]] = None

given TCl[Unit, String] = new TCl {}

Data() match
  case Matches[Unit](x) => println(x)

scastie: https://scastie.scala-lang.org/road21/zxQttu6JT4qdQWgloptmGA/7

Output (click arrow to expand)

java.lang.AssertionError: assertion failed at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:11) at dotty.tools.dotc.core.Decorators$.assertingErrorsReported(Decorators.scala:299) at dotty.tools.dotc.typer.Applications.loop$1(Applications.scala:1587) at dotty.tools.dotc.typer.Applications.loop$1(Applications.scala:1586) at dotty.tools.dotc.typer.Applications.unapplyImplicits$1(Applications.scala:1589) at dotty.tools.dotc.typer.Applications.typedUnApply(Applications.scala:1638) at dotty.tools.dotc.typer.Applications.typedUnApply$(Applications.scala:434) at dotty.tools.dotc.typer.Typer.typedUnApply(Typer.scala:145) at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3496) at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3581) at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3658) at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3662) at dotty.tools.dotc.typer.Typer.typedPattern(Typer.scala:3793) at dotty.tools.dotc.typer.Typer.typedCase(Typer.scala:2228) at dotty.tools.dotc.typer.Typer.typedCases$$anonfun$1(Typer.scala:2154) at dotty.tools.dotc.core.Decorators$.loop$1(Decorators.scala:99) at dotty.tools.dotc.core.Decorators$.mapconserve(Decorators.scala:115) at dotty.tools.dotc.typer.Typer.typedCases(Typer.scala:2153) at dotty.tools.dotc.typer.Typer.$anonfun$39(Typer.scala:2142) at dotty.tools.dotc.typer.Applications.harmonic(Applications.scala:2603) at dotty.tools.dotc.typer.Applications.harmonic$(Applications.scala:434) at dotty.tools.dotc.typer.Typer.harmonic(Typer.scala:145) at dotty.tools.dotc.typer.Typer.typedMatchFinish(Typer.scala:2142) at dotty.tools.dotc.typer.Typer.typedMatch(Typer.scala:2069) at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3511) at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3581) at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3658) at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3662) at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:3773) at dotty.tools.dotc.typer.Namer.typedAheadExpr$$anonfun$1(Namer.scala:1765) at dotty.tools.dotc.typer.Namer.typedAhead(Namer.scala:1755) at dotty.tools.dotc.typer.Namer.typedAheadExpr(Namer.scala:1765) at dotty.tools.dotc.typer.Namer.typedAheadRhs$1$$anonfun$1(Namer.scala:2123) at dotty.tools.dotc.inlines.PrepareInlineable$.dropInlineIfError(PrepareInlineable.scala:256) at dotty.tools.dotc.typer.Namer.typedAheadRhs$1(Namer.scala:2123) at dotty.tools.dotc.typer.Namer.rhsType$1(Namer.scala:2131) at dotty.tools.dotc.typer.Namer.cookedRhsType$1(Namer.scala:2150) at dotty.tools.dotc.typer.Namer.lhsType$1(Namer.scala:2151) at dotty.tools.dotc.typer.Namer.inferredResultType(Namer.scala:2162) at dotty.tools.dotc.typer.Namer.inferredType$1(Namer.scala:1808) at dotty.tools.dotc.typer.Namer.valOrDefDefSig(Namer.scala:1814) at dotty.tools.dotc.typer.Namer$Completer.typeSig(Namer.scala:823) at dotty.tools.dotc.typer.Namer$Completer.completeInCreationContext(Namer.scala:990) at dotty.tools.dotc.typer.Namer$Completer.complete(Namer.scala:859) at dotty.tools.dotc.core.SymDenotations$SymDenotation.completeFrom(SymDenotations.scala:175) at dotty.tools.dotc.core.Denotations$Denotation.completeInfo$1(Denotations.scala:190) at dotty.tools.dotc.core.Denotations$Denotation.info(Denotations.scala:192) at dotty.tools.dotc.core.SymDenotations$SymDenotation.ensureCompleted(SymDenotations.scala:393) at dotty.tools.dotc.typer.Typer.retrieveSym(Typer.scala:3443) at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:3468) at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3580) at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3658) at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3662) at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:3684) at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:3730) at dotty.tools.dotc.typer.Typer.typedBlockStats(Typer.scala:1427) at dotty.tools.dotc.typer.Typer.typedBlock(Typer.scala:1431) at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3504) at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3581) at dotty.tools.dotc.typer.ProtoTypes$FunProto.$anonfun$7(ProtoTypes.scala:534) at dotty.tools.dotc.typer.ProtoTypes$FunProto.cacheTypedArg(ProtoTypes.scala:457) at dotty.tools.dotc.typer.ProtoTypes$FunProto.typedArg(ProtoTypes.scala:535) at dotty.tools.dotc.typer.Applications$ApplyToUntyped.typedArg(Applications.scala:1007) at dotty.tools.dotc.typer.Applications$ApplyToUntyped.typedArg(Applications.scala:1007) at dotty.tools.dotc.typer.Applications$Application.addTyped$1(Applications.scala:688) at dotty.tools.dotc.typer.Applications$Application.matchArgs(Applications.scala:756) at dotty.tools.dotc.typer.Applications$Application.init(Applications.scala:574) at dotty.tools.dotc.typer.Applications$TypedApply.<init>(Applications.scala:882) at dotty.tools.dotc.typer.Applications$ApplyToUntyped.<init>(Applications.scala:1006) at dotty.tools.dotc.typer.Applications.ApplyTo(Applications.scala:1270) at dotty.tools.dotc.typer.Applications.ApplyTo$(Applications.scala:434) at dotty.tools.dotc.typer.Typer.ApplyTo(Typer.scala:145) at dotty.tools.dotc.typer.Applications.simpleApply$1(Applications.scala:1079) at dotty.tools.dotc.typer.Applications.realApply$1$$anonfun$2(Applications.scala:1189) at dotty.tools.dotc.typer.Typer$.tryEither(Typer.scala:118) at dotty.tools.dotc.typer.Applications.realApply$1(Applications.scala:1204) at dotty.tools.dotc.typer.Applications.typedApply(Applications.scala:1244) at dotty.tools.dotc.typer.Applications.typedApply$(Applications.scala:434) at dotty.tools.dotc.typer.Typer.typedApply(Typer.scala:145) at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3496) at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3581) at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3658) at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3662) at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:3711) at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:3730) at dotty.tools.dotc.typer.Typer.typedClassDef(Typer.scala:3160) at dotty.tools.dotc.typer.Typer.typedTypeOrClassDef$1(Typer.scala:3484) at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:3488) at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3580) at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3658) at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3662) at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:3684) at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:3730) at dotty.tools.dotc.typer.Typer.typedPackageDef(Typer.scala:3293) at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3530) at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3581) at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3658) at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3662) at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:3773) at dotty.tools.dotc.typer.TyperPhase.typeCheck$$anonfun$1(TyperPhase.scala:47) at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15) at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10) at dotty.tools.dotc.core.Phases$Phase.monitor(Phases.scala:507) at dotty.tools.dotc.typer.TyperPhase.typeCheck(TyperPhase.scala:53) at dotty.tools.dotc.typer.TyperPhase.$anonfun$4(TyperPhase.scala:99) at scala.collection.Iterator$$anon$6.hasNext(Iterator.scala:479) at scala.collection.Iterator$$anon$9.hasNext(Iterator.scala:583) at scala.collection.immutable.List.prependedAll(List.scala:152) at scala.collection.immutable.List$.from(List.scala:685) at scala.collection.immutable.List$.from(List.scala:682) at scala.collection.IterableOps$WithFilter.map(Iterable.scala:900) at dotty.tools.dotc.typer.TyperPhase.runOn(TyperPhase.scala:98) 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.xsbt.CompilerBridgeDriver.run(CompilerBridgeDriver.java:141) at dotty.tools.xsbt.CompilerBridge.run(CompilerBridge.java:22) at sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:91) at sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$7(MixedAnalyzingCompiler.scala:196) at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23) at sbt.internal.inc.MixedAnalyzingCompiler.timed(MixedAnalyzingCompiler.scala:252) at sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4(MixedAnalyzingCompiler.scala:186) at sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4$adapted(MixedAnalyzingCompiler.scala:166) at sbt.internal.inc.JarUtils$.withPreviousJar(JarUtils.scala:241) at sbt.internal.inc.MixedAnalyzingCompiler.compileScala$1(MixedAnalyzingCompiler.scala:166) at sbt.internal.inc.MixedAnalyzingCompiler.compile(MixedAnalyzingCompiler.scala:214) at sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1(IncrementalCompilerImpl.scala:542) at sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1$adapted(IncrementalCompilerImpl.scala:542) at sbt.internal.inc.Incremental$.$anonfun$apply$3(Incremental.scala:182) at sbt.internal.inc.Incremental$.$anonfun$apply$3$adapted(Incremental.scala:180) at sbt.internal.inc.Incremental$$anon$2.run(Incremental.scala:458) at sbt.internal.inc.IncrementalCommon$CycleState.next(IncrementalCommon.scala:117) at sbt.internal.inc.IncrementalCommon$$anon$1.next(IncrementalCommon.scala:56) at sbt.internal.inc.IncrementalCommon$$anon$1.next(IncrementalCommon.scala:52) at sbt.internal.inc.IncrementalCommon.cycle(IncrementalCommon.scala:263) at sbt.internal.inc.Incremental$.$anonfun$incrementalCompile$8(Incremental.scala:413) at sbt.internal.inc.Incremental$.withClassfileManager(Incremental.scala:500) at sbt.internal.inc.Incremental$.incrementalCompile(Incremental.scala:400) at sbt.internal.inc.Incremental$.apply(Incremental.scala:208) at sbt.internal.inc.IncrementalCompilerImpl.compileInternal(IncrementalCompilerImpl.scala:542) at sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileIncrementally$1(IncrementalCompilerImpl.scala:496) at sbt.internal.inc.IncrementalCompilerImpl.handleCompilationError(IncrementalCompilerImpl.scala:332) at sbt.internal.inc.IncrementalCompilerImpl.compileIncrementally(IncrementalCompilerImpl.scala:433) at sbt.internal.inc.IncrementalCompilerImpl.compile(IncrementalCompilerImpl.scala:137) at sbt.Defaults$.compileIncrementalTaskImpl(Defaults.scala:2443) at sbt.Defaults$.$anonfun$compileIncrementalTask$2(Defaults.scala:2393) at sbt.internal.server.BspCompileTask$.$anonfun$compute$1(BspCompileTask.scala:41) at sbt.internal.io.Retry$.apply(Retry.scala:47) at sbt.internal.io.Retry$.apply(Retry.scala:29) at sbt.internal.io.Retry$.apply(Retry.scala:24) at sbt.internal.server.BspCompileTask$.compute(BspCompileTask.scala:41) at sbt.Defaults$.$anonfun$compileIncrementalTask$1(Defaults.scala:2391) at scala.Function1.$anonfun$compose$1(Function1.scala:49) at sbt.internal.util.$tilde$greater.$anonfun$$u2219$1(TypeFunctions.scala:63) at sbt.std.Transform$$anon$4.work(Transform.scala:69) at sbt.Execute.$anonfun$submit$2(Execute.scala:283) at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:24) at sbt.Execute.work(Execute.scala:292) at sbt.Execute.$anonfun$submit$1(Execute.scala:283) at sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:265) at sbt.CompletionService$$anon$2.call(CompletionService.scala:65) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:840)``` ```
@road21 road21 added itype:bug itype:crash stat:needs triage Every issue needs to have an "area" and "itype" label labels Feb 7, 2025
@Gedochao Gedochao added area:typer and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Feb 11, 2025
@mbovel
Copy link
Member

mbovel commented Feb 23, 2025

This issue was picked for the Scala Issue Spree of tomorrow, Monday, February 24th. @SethTisue, @kyouko-taiga and @mbovel will be working on it. If you have any insight into the issue or guidance on how to fix it, please leave it here.

@mbovel
Copy link
Member

mbovel commented Feb 24, 2025

Minimized to:

object Matches:
  def unapply(y: Any)[T]: Option[Any] = None

def main =
  42 match
    case Matches(x) => println(x)

However, moving the type parameter makes is compile:

object Matches:
  def unapply[T](y: Any): Option[Any] = None

def main =
  42 match
    case Matches(x) => println(x)

@mbovel
Copy link
Member

mbovel commented Feb 24, 2025

Error case:

TypeApply(Apply(Select(Ident(Matches),unapply),List(Literal(Constant(null)))),List(TypeTree[TypeVar(TypeParamRef(T))]))

Happy case:

Apply(TypeApply(Select(Ident(Matches),unapply),List(TypeTree[TypeVar(TypeParamRef(T))])),List(Literal(Constant(null))))

@mbovel
Copy link
Member

mbovel commented Feb 24, 2025

@Sporarum do you think that should be accepted? 😄

The problem is that the Unapply node cannot store type arguments. In the case where we have object Foo { def unapply[T](x: Any): Option[Any] }, it's not problem because we can reduce the call to Any => Option[Any] by passing the type argument. But when the type argument is after as in object Foo { def unapply(x: Any)[T]: Option[Any] }, it's not clear what we should do.

@kyouko-taiga
Copy link
Contributor

Martin thinks that we should not support type parameters after parameter lists for unapply methods.

@Sporarum
Copy link
Contributor

For me the question resides in:
How useful are path dependent usings in unapply methods ?

If they are not useful, there's no need to support this pattern

If they are useful (and have no good alternatives), then we should support this feature

Regardless, the compiler should not crash ^^"

@mbovel mbovel linked a pull request Mar 3, 2025 that will close this issue
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.

5 participants