Skip to content

Fixes for capture checking case class methods - #25278

Merged
odersky merged 4 commits into
scala:mainfrom
dotty-staging:fix-23823
Feb 25, 2026
Merged

Fixes for capture checking case class methods#25278
odersky merged 4 commits into
scala:mainfrom
dotty-staging:fix-23823

Conversation

@odersky

@odersky odersky commented Feb 15, 2026

Copy link
Copy Markdown
Contributor

Fixes #23823.

We special treat primary constructors when we compute the result capture set. We need to do the same for case class apply and copy methods.

The result type is patched when we instantiate one of these methods with arguments. I tried to do that as a transform of the info of these methods instead. That almost worked, but failed because of the unbox operation needed in refineConctructorInstance which needs to know the actual arguments. This is a tricky bit. I added some comments to refineConctructorInstance.

As part of this amandoned attempt to work on info transformers in Setup, I moved a lot of machinery needed by
refineConctructorInstance from CheckCaptures into CaptureOps. It's not strictly necessary to do that since in the final PR the only root call is from CheckCaptures. But it might be needed later, so kept the refactoring.

These fell through the cracks before.

There's still a hole: External global objects don't get their capture set implied by fields. So if
they do not extend a Capability trait they are deemed pure, even if they contain capability fields.
See console-use in pending tests.

There are two ways to fix this:

 - Also do capturesImpliedByFields for global objects so that their capset is computed structurally.
 - Or, require that global objects with capability fields extend the appropriate capability class.
@Linyxus

Linyxus commented Feb 22, 2026

Copy link
Copy Markdown
Contributor

Is this ready-for-review?

@odersky

odersky commented Feb 22, 2026

Copy link
Copy Markdown
Contributor Author

Yes, ready for review

@odersky

odersky commented Feb 25, 2026

Copy link
Copy Markdown
Contributor Author

@Linyxus ping for review

@odersky
odersky merged commit 7c615a4 into scala:main Feb 25, 2026
60 checks passed
@odersky
odersky deleted the fix-23823 branch February 25, 2026 10:46
odersky added a commit that referenced this pull request Mar 24, 2026
If a class extends a Capability, it will now get a LocalCap on creation.
This
solves the problem that
```scala
  class C extends Capability
  val a = C()
  val b: C = C()
```
did two different things: `a` was pure but `b` was impure. Now they are
both impure.

Based on #25278 

Also, several other new rules around capture sets of `new`, outlined on
the doc page.
@WojciechMazur WojciechMazur added this to the 3.8.4 milestone Mar 31, 2026
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.

Local fresh caps are ignored in classes

4 participants