Skip to content

CapSet Type-Variable Bounds Crash the Capture Checker #22437

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

Closed
bracevac opened this issue Jan 22, 2025 · 3 comments · Fixed by #22451
Closed

CapSet Type-Variable Bounds Crash the Capture Checker #22437

bracevac opened this issue Jan 22, 2025 · 3 comments · Fixed by #22451
Assignees
Labels
area:experimental:cc Capture checking related cc-experiment Intended to be merged with cc-experiment branch on origin itype:bug itype:crash
Milestone

Comments

@bracevac
Copy link
Contributor

bracevac commented Jan 22, 2025

Compiler version

Latest nightly

Minimized code

With the recents improvements involving capture variables, we now have two ways to write down a capture variable's bounds, e.g.,

def mixedBounds[A^, B >: CapSet <: A, C >: CapSet <: CapSet^{B^}] = ???

C's bound can also be written as simply <: B. However, with the bound
<: CapSet^{B^} the setup phase of the capture checker crashes while
executing the integrateRT method.

It would be nice to support the CapSet^{B^} notation, since one expects
to be able to provide a non-singleton bound, e.g., C <: CapSet^{a,b,c}.

Output (click arrow to expand)

Exception in thread "main" java.lang.AssertionError: assertion failed: not a trackable captureRef ref: B, [B, <notype>]

  unhandled exception while running cc on tests/neg-custom-args/captures/capture-vars-subtyping.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: local/capture-bounds.scala
        during phase: cc
                mode: Mode(ImplicitsEnabled)
     library version: version 2.13.16
    compiler version: version 3.7.0-RC1-bin-SNAPSHOT-nonbootstrapped-git-c3fcd7c
            settings: -classpath /Users/oliver/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.16/scala-library-2.13.16.jar:/Users/oliver/projects/scala3/library/../out/bootstrap/scala3-library-bootstrapped/scala-3.7.0-RC1-bin-SNAPSHOT-nonbootstrapped/scala3-library_3-3.7.0-RC1-bin-SNAPSHOT.jar -d /Users/oliver/projects/scala3/compiler/../out/default-last-scalac-out.jar

        at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
        at dotty.tools.dotc.core.Types$BiTypeMap.ensureTrackable$1(Types.scala:6085)
        at dotty.tools.dotc.core.Types$BiTypeMap.forward(Types.scala:6086)
        at dotty.tools.dotc.core.Types$BiTypeMap.forward$(Types.scala:6069)
        at dotty.tools.dotc.cc.Setup$SubstParams.forward(Setup.scala:384)
        at dotty.tools.dotc.cc.CaptureSet.$anonfun$6(CaptureSet.scala:293)
        at dotty.tools.dotc.util.SimpleIdentitySet$Set1.map(SimpleIdentitySet.scala:86)
        at dotty.tools.dotc.cc.CaptureSet.map(CaptureSet.scala:293)
        at dotty.tools.dotc.core.Types$TypeMap.mapCapturingType(Types.scala:6168)
        at dotty.tools.dotc.core.Types$TypeMap.mapOver(Types.scala:6221)
        at dotty.tools.dotc.cc.Setup$SubstParams.apply(Setup.scala:401)
        at dotty.tools.dotc.core.Types$TypeMap.mapOver(Types.scala:6212)
        at dotty.tools.dotc.cc.Setup$SubstParams.apply(Setup.scala:401)
        at dotty.tools.dotc.cc.Setup$$anon$4.integrateRT$1$$anonfun$1$$anonfun$1(Setup.scala:583)
        at scala.collection.immutable.List.map(List.scala:251)
        at dotty.tools.dotc.cc.Setup$$anon$4.integrateRT$1$$anonfun$1(Setup.scala:583)
        at dotty.tools.dotc.core.Types$PolyType.<init>(Types.scala:4346)
        at dotty.tools.dotc.core.Types$PolyType$.apply(Types.scala:4456)
        at dotty.tools.dotc.core.Types$PolyType$.apply(Types.scala:4453)
        at dotty.tools.dotc.cc.Setup$$anon$4.integrateRT$1(Setup.scala:586)
        at dotty.tools.dotc.cc.Setup$$anon$4.postProcess(Setup.scala:598)
        at dotty.tools.dotc.cc.Setup$$anon$4.traverse(Setup.scala:513)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.recur$2(tpd.scala:1339)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1342)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1334)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverse(Trees.scala:1800)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.recur$2(tpd.scala:1340)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1342)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1334)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverse(Trees.scala:1800)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.recur$2(tpd.scala:1340)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1342)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1334)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverse(Trees.scala:1800)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.recur$2(tpd.scala:1340)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1342)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1334)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverse(Trees.scala:1800)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.recur$2(tpd.scala:1340)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1342)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1334)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverse(Trees.scala:1800)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.recur$2(tpd.scala:1340)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1342)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1334)
        at dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.foldOver(Trees.scala:1760)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverseChildren(Trees.scala:1802)
        at dotty.tools.dotc.cc.Setup$$anon$4.traverse(Setup.scala:512)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1801)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1801)
        at dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.foldOver(Trees.scala:1757)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverseChildren(Trees.scala:1802)
        at dotty.tools.dotc.cc.Setup$$anon$4.traverse(Setup.scala:502)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.recur$2(tpd.scala:1339)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1342)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1334)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverse(Trees.scala:1800)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.recur$2(tpd.scala:1340)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1342)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1334)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverse(Trees.scala:1800)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.recur$2(tpd.scala:1340)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1342)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1334)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverse(Trees.scala:1800)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.recur$2(tpd.scala:1340)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1342)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1334)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverse(Trees.scala:1800)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.recur$2(tpd.scala:1340)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1342)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1334)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverse(Trees.scala:1800)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.recur$2(tpd.scala:1337)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1342)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1334)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverse(Trees.scala:1800)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.recur$2(tpd.scala:1337)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1342)
        at dotty.tools.dotc.ast.tpd$TreeTraverserWithPreciseImportContexts.apply(tpd.scala:1334)
        at dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.foldOver(Trees.scala:1766)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverseChildren(Trees.scala:1802)
        at dotty.tools.dotc.cc.Setup$$anon$4.traverse(Setup.scala:512)
        at dotty.tools.dotc.cc.Setup.setupUnit(Setup.scala:837)
        at dotty.tools.dotc.cc.CheckCaptures$CaptureChecker.checkUnit(CheckCaptures.scala:1548)
        at dotty.tools.dotc.transform.Recheck.run(Recheck.scala:149)
        at dotty.tools.dotc.cc.CheckCaptures.run(CheckCaptures.scala:258)
        at dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:383)
        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:376)
        at dotty.tools.dotc.transform.Recheck.runOn(Recheck.scala:153)
        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:1324)
        at dotty.tools.dotc.Run.runPhases$1(Run.scala:336)
        at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:383)
        at dotty.tools.dotc.Run.compileUnits$$anonfun$adapted$1(Run.scala:395)
        at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:69)
        at dotty.tools.dotc.Run.compileUnits(Run.scala:395)
        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)
@bracevac bracevac added area:experimental:cc Capture checking related cc-experiment Intended to be merged with cc-experiment branch on origin itype:bug itype:crash labels Jan 22, 2025
@Linyxus
Copy link
Contributor

Linyxus commented Jan 24, 2025

I had a look. The problem seems to be with ensureTrackable in BiTypeMap at Types.scala: in integrateRT when mapping parameter references we use a BiTypeMap, which, when applied, calls ensureTrackable to assert that the results are trackable capture references. However, in integrateRT at this callsite, the info of TypeParamRef is not reliable (it seems to be NoType) as the lambda is still being formed. So this assertion always fails.

This assertion seems a sanity check, and not essential for checking the wellformedness of capture sets. Given that the info of TypeParamRef at that moment is not informative enough for us to properly perform this check, maybe we should fix this issue by temporarily disabling this assert?

bracevac added a commit to dotty-staging/dotty that referenced this issue Jan 24, 2025
Fixes scala#22437

The check crashes the compiler when mapping over a capture variable
in an upper bound of the form `CapSet^{C^}` as well as
path captures in function signatures. See the test
`capture-vars-subtyping2.scala` for examples.
@noti0na1
Copy link
Member

The current integrateRT is not able to handle depedent parameters (both type and term) in the same list, because the mapped ref is refering to a method type which is still under constructing.

@bracevac
Copy link
Contributor Author

bracevac commented Jan 25, 2025

It does work when we remove the isTrackableRef checks in BiTypeMap #22451. The change does not break any tests. Can we find an example that shows we need the retain the check?

Edit: I left the check in place, and instead skip it only for type and term refs that have no info.

@bracevac bracevac self-assigned this Jan 29, 2025
odersky added a commit that referenced this issue Feb 17, 2025
…ap (#22451)

Fixes #22437

The check crashes the compiler when mapping over a capture variable in
an upper bound of the form `CapSet^{C^}` as well as path captures in
function signatures. See the test `capture-vars-subtyping2.scala` for
examples.
@WojciechMazur WojciechMazur added this to the 3.7.0 milestone Mar 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:experimental:cc Capture checking related cc-experiment Intended to be merged with cc-experiment branch on origin itype:bug itype:crash
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants