Skip to content

Fix #25894: break cross-unit cyclic export on partial recompile#25900

Open
soronpo wants to merge 2 commits intoscala:mainfrom
soronpo:fix_i25894
Open

Fix #25894: break cross-unit cyclic export on partial recompile#25900
soronpo wants to merge 2 commits intoscala:mainfrom
soronpo:fix_i25894

Conversation

@soronpo
Copy link
Copy Markdown
Contributor

@soronpo soronpo commented Apr 22, 2026

When a file is recompiled against TASTy of its sibling files, resolving an import on the enclosing package can chain into an export in a loaded-from-TASTy sibling that points back at a definition in the file currently being typed, producing a spurious Cyclic reference involving val <import>.

In typedPackageDef, after completing the current source's <src>$package class (existing behaviour for i13669), also force-complete any sibling <src>$package classes in this package that came from the classpath. This pre-resolves their exports before any import in the current file runs its completer, breaking the cycle.

Narrowed to avoid unnecessary work:

  • skipped for the root / empty package (i13669 is unaffected — it uses the existing top-level call);
  • only isDefinedInBinary $package classes are forced, so source- defined siblings still complete in their natural order.

Fixes #25894

How much have you relied on LLM-based tools in this contribution?

Extensively, but the change is very short. The minimization was hell on earth, even with the help of AI to minimize a 10,000 LOC incremental compilation issue that only happens in sbtn on Windows to 60 LOC that surface the bug without sbt dependency and work on Linux as well.

How was the solution tested?

New automated tests (including the issue's reproducer, if applicable)

soronpo and others added 2 commits April 22, 2026 16:39
When a file is recompiled against TASTy of its sibling files, resolving
an import on the enclosing package can chain into an export in a
loaded-from-TASTy sibling that points back at a definition in the file
currently being typed, producing a spurious `Cyclic reference involving
val <import>`.

In `typedPackageDef`, after completing the current source's
`<src>$package` class (existing behaviour for i13669), also force-complete
any sibling `<src>$package` classes in this package that came from the
classpath. This pre-resolves their exports before any import in the
current file runs its completer, breaking the cycle.

Narrowed to avoid unnecessary work:
- skipped for the root / empty package (i13669 is unaffected — it uses
  the existing top-level call);
- only `isDefinedInBinary` `$package` classes are forced, so source-
  defined siblings still complete in their natural order.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…scala#25797)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@soronpo soronpo marked this pull request as ready for review April 22, 2026 17:05
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

Successfully merging this pull request may close these issues.

Incremental compile: Cyclic reference involving val <import>

1 participant